与Java 6相比,Java 8的GUI性能较差

Mit*_*urt 31 java performance user-interface swing java-8

在下面的Java 6中,代码按预期运行,但在Java 8中,它需要花费更多的时间.有趣的是,组件使用相同的方法setEnable()来启用和禁用组件,但禁用调用所需的时间比启用组件要长得多,几乎是后者的两倍.Java 8中的禁用时间比Java 1.6中的禁用时间长.问题是为什么会发生这种情况?这是Java 8的性能问题吗?

以下是Java 6的结果:

    Sun Microsystems Inc. 1.6.0_45
    Initializing GUI
    GUI initialized in 1105 ms
    Disabling
    Disabled in 687 ms
    Enabling
    Enabled in 375 ms
Run Code Online (Sandbox Code Playgroud)

以下是Java 8的结果:

    Oracle Corporation 1.8.0_25
    Initializing GUI
    GUI initialized in 604 ms
    Disabling
    Disabled in 6341 ms
    Enabling
    Enabled in 370 ms
Run Code Online (Sandbox Code Playgroud)

代码:

import java.awt.Component;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class TestGUI extends JFrame implements ActionListener {

    private static final long serialVersionUID = 1L;

    public TestGUI() {
        initGUI();
    }

    public void actionPerformed(ActionEvent e) {
        String text;
        if(e.getActionCommand().equals("Enable-ALL")){
            enableAll();
            text= "Disable-ALL";
        }
        else{
            disableAll();
            text= "Enable-ALL";
        }
        ((JButton)e.getSource()).setText(text);
        ((JButton)e.getSource()).setEnabled(true);

    }


    private  void initGUI() {
        long m = System.currentTimeMillis();
        System.out.println("Initializing GUI");
        setTitle(System.getProperty("java.vendor") + " " + System.getProperty("java.version"));
        setLayout(new FlowLayout());

        JButton b = new JButton("Disable-ALL ");
        b.addActionListener(this);
        add(b);

        for (int i = 1; i < 10001; i++) {
            b = new JButton("Button " + i);
            add(b);
        }
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600, 600);
        setVisible(true);
        m = System.currentTimeMillis() - m;
        System.out.println("GUI initialized in " + m + " ms");
    }

    private void disableAll() {
        long m = System.currentTimeMillis();
        System.out.println("Disabling");
        for (Component c : getContentPane().getComponents()) {
            c.setEnabled(false);
        }

        m = System.currentTimeMillis() - m;
        System.out.println("Disabled in " + m + " ms");
    }

    private void enableAll() {
        long m = System.currentTimeMillis();
        System.out.println("Enabling");
        for (Component c : getContentPane().getComponents()) {
            c.setEnabled(true);
            invalidate();
        }
        m = System.currentTimeMillis() - m;
        System.out.println("Enabled in " + m + " ms");
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                System.out.println(System.getProperty("java.vendor") + " "
                        + System.getProperty("java.version"));
                new TestGUI();
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 25

根据我的分析器,操作大部分时间都花费在方法中Thread.holdsLock,这实际上是一种代价高昂的操作,Component.checkTreeLock其被称为间接调用Component.updateCursorImmediately.

通常,您可以通过getContentPane().setVisible(false);在操作之前和getContentPane().setVisible(true);之后立即调用来更新多个组件,从而避免代价高昂的视觉更新,例如

private void disableAll() {
    long m = System.currentTimeMillis();
    System.out.println("Disabling");
    getContentPane().setVisible(false);
    for (Component c : getContentPane().getComponents()) {
        c.setEnabled(false);
    }
    getContentPane().setVisible(true);

    m = System.currentTimeMillis() - m;
    System.out.println("Disabled in " + m + " ms");
}
Run Code Online (Sandbox Code Playgroud)

您将看到,无论哪种视觉更新导致问题详细,这些问题都将消失.

所以你不需要考虑如何在这里正确地进行基准测试,而不是在操作需要几秒钟时这很重要,但我建议学习之间的区别System.currentTimeMillis(),System.nanoTime()因为后者是测量经过时间的正确工具.

  • 您可以向Oracle提交错误报告,以解决如此严重的性能问题.但即使在下一版本中修复了它,您也必须决定如何使用受问题影响的版本来处理用户.对我来说,这不是第一次更新将以前简单的操作转换为冗长的操作,即使在较小的更新中也可能发生.所以坏消息是,GUI编程是解决方案编程.我不太了解您的申请,以提供更具体的建议.但是如果你得到一个异步事件,你必须在EDT上放一些动作,这样你就可以控制它...... (4认同)
  • 1.甲骨文从Sun收购Java,忽略了AWT/Swing,2.图形算法,渲染逻辑是史前的,3.核心针对当今的JavaFX进行了优化,具有接近今天的渲染逻辑和相当好的GPU优化(在所有情况下)比使用AWT/Swing API更好,4.这里有一些半缺陷,对应部分旧API缺少优化 (3认同)
  • @mKorbel:我们尝试了JavaFX来完成一些现实生活中的任务,并在测试结束后将其作为一个糟糕的笑话.我无法理解为什么这些开发人员喜欢已经失败的Java3D和Java Media Framework的场景图概念.问题不在于JavaFX比AWT/Swing(在关键部分)有更多的错误,但你甚至无法解决这些错误,因为你无法执行外汇开发人员未预见的任何行动(显然他们有一个非常狭隘的观点).好吧,如果你想使用CSS让非工作用户界面看起来很漂亮,你就去... (3认同)

ome*_*dat 5

I haven't had a chance to understand exactly, but it seems like event handling might have changed in 8. Disabling the parent first speeds up the process:

getContentPane().setEnabled(false);
for (Component c : getContentPane().getComponents()) {
    c.setEnabled(false);
}
getContentPane().setEnabled(true);
Run Code Online (Sandbox Code Playgroud)