Swing Thread Safe Programming

后端 未结 1 1506
长情又很酷
长情又很酷 2020-12-19 07:56
public static void main(String args[]) {
    /* Set the Nimbus look and feel */
    //

        
相关标签:
1条回答
  • 2020-12-19 08:43

    Nothing theoretical about it. It's very practical. The SwingUtilities.invokeLater() method guarantees that the code within the Runnable will run on the Event Dispatch Thread (EDT). This is important because Swing is not thread-safe, thus anything related to the GUI (Swing, etc.) needs to run on the EDT. The EDT is a "it happens whenever it happens" thread that makes no guarantees about the order in which things are executed. If the GUI code is executed within a background thread (say, within a SwingWorker instance), then it can throw errors. I learned this the hard way: in my learning years, executing GUI-changing code within a background thread caused random, inconsistent RuntimeExceptions that I couldn't figure out. It was a good learning experience (SwingWorker has a doInBackground() method for background tasks and a done() method for EDT tasks).

    In the same way you don't want to execute GUI code on a background thread, you also don't want to execute large operations (database queries, etc) on the EDT. This is because the EDT is dispatching all of the GUI events so everything on the EDT should be very short and sweet. You can easily see this with a JProgressBar set to indeterminate.

    This SSCCE should illustrate it nicely. Notice the motion of the JProgressBar as method() is called, once on a background thread and once on a EDT thread.

    import javax.swing.JFrame;
    import javax.swing.JProgressBar;
    import javax.swing.SwingWorker;
    
    /**
     *
     * @author Ryan
     */
    public class Test {
    
        public static void main(String args[]) {
            JFrame frame = new JFrame();
            JProgressBar jpb = new JProgressBar();
            jpb.setIndeterminate(true);
            frame.add(jpb);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            new Task().execute();
        }
    
        public static void method() { // This is a method that does a time-consuming task.
            for(int i = 1; i <= 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i);
            }
        }
    
        static class Task extends SwingWorker<Void, Void> {
    
            @Override
            protected Void doInBackground() throws Exception {
                /* Executing method on background thread.
                 * The loading bar should keep moving because, although method() is time consuming, we are on a background thread.
                */ 
                method();
                return null;
            }
    
            @Override
            protected void done() {
                /* Executing method on Event Dispatch Thread.
                 * The loading bar should stop because method() is time consuming and everything on the Event Dispatch Thread
                 * (like the motion of the progress bar) is waiting for it to finish.
                */
    
                // 
                method();
            }
        }
    }
    

    Hope this helps.

    0 讨论(0)
提交回复
热议问题