2015-01-20 56 views
30

Trong Java 6 dưới đây mã đang chạy như mong đợi nhưng trong Java 8 nó đang mất nhiều thời gian hơn. Phần thú vị là các thành phần sử dụng cùng phương thức setEnable() để kích hoạt và vô hiệu hóa các thành phần, nhưng cuộc gọi vô hiệu hóa mất nhiều thời gian hơn kích hoạt cho phép, gần gấp đôi. Vô hiệu hóa trong Java 8 mất nhiều thời gian hơn so với một trong Java 1.6. Câu hỏi đặt ra là tại sao điều này lại xảy ra? Đây có phải là vấn đề về hiệu năng của Java 8 không?Java 8 kém hiệu suất GUI so với Java 6

Dưới đây là các kết quả cho 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 

Dưới đây là các kết quả cho 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 

Mã:

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(); 
      } 
     }); 
    } 
} 
+4

Đó không phải là cách để đo lường hiệu suất cho Các ứng dụng Java. Hiện tại bạn bao gồm chi phí thời gian tải lớp chỉ xảy ra một lần. Sử dụng thư viện JMH cho các tiêu chuẩn vi mô – Vic

+4

Có bạn là đúng này không phải là một điểm chuẩn .. Tuy nhiên Là một người dùng tôi có thể cảm thấy sự chậm chạp. Như bạn có thể thấy trong Java 1.8 vô hiệu hóa là trong 6341 ms trong khi kích hoạt là 370 ms. Họ đang sử dụng cùng phương thức setEnable(). Tại sao điều này xảy ra? – mbsau

+2

6 giây là rất nhiều thời gian - bạn có nhận được các số liệu tương tự nếu bạn chạy nó một vài lần không? – assylias

Trả lời

24

Theo hồ sơ của tôi, hoạt động phần lớn thời gian trong phương thức Thread.holdsLock, có thể thực sự là một hoạt động tốn kém, được gọi là Component.checkTreeLock được gọi gián tiếp bởi Component.updateCursorImmediately.

Nói chung, bạn có thể tránh các cập nhật trực quan tốn kém khi cập nhật nhiều thành phần bằng cách gọi getContentPane().setVisible(false); ngay trước hoạt động và getContentPane().setVisible(true); ngay sau đó, ví dụ:

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"); 
} 

Bạn sẽ thấy, các vấn đề như vậy sẽ biến mất, bất kể loại cập nhật trực quan nào gây ra sự cố chi tiết. Vì vậy, bạn không cần phải suy nghĩ về cách đánh giá chính xác ở đây, điều đó không quan trọng khi hoạt động mất vài giây, nhưng tôi khuyên bạn nên tìm hiểu sự khác biệt giữa System.currentTimeMillis()System.nanoTime() vì sau này là công cụ thích hợp để đo trôi qua thời gian.

+0

cảm ơn Holger Trong ứng dụng của chúng tôi, không có số thành phần nào trong một khung nhìn như mẫu mã trên. Sự hòa bình mã nhỏ này tái tạo vấn đề hiệu năng gui của chúng tôi. Vấn đề thực tế của chúng tôi là khi bản cập nhật của thành phần (hoặc Khung) sau khi dữ liệu được hiển thị lấy từ máy chủ. Dữ liệu đang nhận được từ máy chủ theo cách không đồng bộ. Có thể có nhiều hơn một yêu cầu tìm nạp dữ liệu đi đến máy chủ khi khởi tạo khung. Vì vậy, không có điểm nào cho phương thức getContentPane(). SetVisible() trong các tình huống này. Tôi có thực sự cần thay đổi mã không? Bởi vì nó hoạt động tốt ở java 1.6. – mbsau

+4

Bạn có thể gửi báo cáo lỗi cho Oracle về vấn đề hiệu suất của cường độ này. Nhưng ngay cả khi nó được sửa trong phiên bản tiếp theo, bạn phải quyết định cách xử lý người dùng bằng phiên bản bị ảnh hưởng bởi sự cố. Đối với tôi, đây không phải là lần đầu tiên bản cập nhật biến một thao tác đơn giản trước đó thành một thao tác dài, điều đó có thể xảy ra ngay cả khi cập nhật nhỏ. Vì vậy, tin xấu là, lập trình GUI là lập trình xung quanh. Tôi không biết đủ về đơn đăng ký của bạn để đưa ra lời khuyên cụ thể hơn. Nhưng nếu bạn nhận được một sự kiện không đồng bộ, bạn phải đặt một số hành động trên EDT tại một thời điểm để bạn kiểm soát nó… – Holger

+3

1. AWT/Swing bị bỏ qua bởi Oracle từ việc tiếp quản Java từ Sun, 2. thuật toán đồ họa, kết xuất logics là thời tiền sử, 3. core được tối ưu hóa cho JavaFX ngày nay với tối ưu hóa render todays và tối ưu hóa khá tốt cho GPU (trong mọi trường hợp tốt hơn có thể bằng cách sử dụng API AWT/Swing), 4. đây là một vài lỗi tương ứng tối ưu hóa cho một phần của API cũ – mKorbel

5

tôi đã không có cơ hội để hiểu chính xác, nhưng nó có vẻ như xử lý sự kiện có thể đã thay đổi trong 8. Vô hiệu hóa phụ huynh đầu tiên tăng tốc quá trình:

getContentPane().setEnabled(false); 
for (Component c : getContentPane().getComponents()) { 
    c.setEnabled(false); 
} 
getContentPane().setEnabled(true);