Analysis on Swing thread model and EDT

Source: Internet
Author: User

Recently I used Swing to write a test tool. when reading the codes of the software I want to test, I found that he used SwingUtilities's invokelater method in a lot of ways when updating the UI. I used to do less Swing applications in the past, and I wrote a few Swing programs in the university era. I remember that I directly created frames and updated interfaces in the main method.

In the past, I wrote:

Code
import java.awt.Color;



import javax.swing.*;



public class OldSwingDemo {



  public static void main(String[] argv) {


    JLabel bulletin = new JLabel("Hello,World!", JLabel.CENTER);



    JFrame frame = new JFrame("Bulletin");


    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


    frame.getContentPane().add(bulletin);


    frame.setSize(200, 150);


    frame.setVisible(true);


    bulletin.setForeground(Color.RED);


 


  }


}

 

So I carefully searched the relevant information and learned about Swing's single-threaded model and EDT (Event-Dispatch-Thread), only to find that my original practice is very dangerous. I will summarize it as follows:

Java Swing is a single-thread graphics library. The vast majority of the Code in it is not thread-safe. Let's look at the APIs of various Swing components, you can find that the vast majority of threads, such as synchronization, are not processed securely. This means that it is not called anywhere (if you are not doing an experiment ), you can use these APIs in different threads to update interface elements, such as setting values. Updating colors may cause problems.

Although Swing APIs are NOT thread-safe, if you write code according to the specification (this specification is described later), the Swing framework uses other methods to ensure thread security, that is, Event Queue and EDT, let's first look at a picture:

 

We can see from the image that the request events sent on the GUI, such as window movement, refresh, and Button clicking, whether single or concurrent, will be put into the Event Queue) and the Event dispatching Thread will extract them one by one and Dispatch them to the corresponding Event processing method. Previously we mentioned that Swing is a single-threaded graphical package because there is only one event distribution thread for processing GUI events. As long as you do not stop this GUI program, EDT will continuously process requests.

What are the benefits of this single-thread queue model? In the Java UI of ITPUB, the Swing event distribution thread summarizes two points:

(1) convert a synchronization operation to an Asynchronous Operation

(2) Converting parallel processing into sequential processing

I think I can add one more point: (3) interface programming is greatly simplified. If it is a multi-threaded model, all event processing will be performed in an asynchronous thread, so synchronous access to interface elements will be handled by developers themselves. It is also complicated to think about, so it is no wonder that most of the current GUI frameworks use this single-threaded model.

So what do we need to pay attention to and follow?

In JFC Swing Tutorial, we made a good conclusion on how to maintain the "thread security of operating GUI code:

To avoid the possibility of deadlock, you must take extreme care that Swing components and models are modified or queried only from the event-dispatching thread. as long as your program creates its GUI from the event-dispatching thread and modifies the GUI only from event handlers, it is thread safe.

As long as you create a GUI in EDT and modify the GUI in the event processor, your code is thread-safe in Swing.

Therefore, the preceding code should be modified as follows:

Code
import java.awt.Color;



import javax.swing.JFrame;


import javax.swing.JLabel;


import javax.swing.SwingUtilities;



public class NewSwingDemo {


  public static void main(String[] argv) {



    SwingUtilities.invokeLater(new Runnable() {



      @Override


      public void run() {


        constructUI();


            }


    });



  }



  private static void constructUI() {


    JLabel bulletin = new JLabel("Hello,World!", JLabel.CENTER);



    JFrame frame = new JFrame("Bulletin");


    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


    frame.getContentPane().add(bulletin);


    frame.setSize(200, 150);


    frame.setVisible(true);


    bulletin.setForeground(Color.RED);



  }


}

In addition to thread security, we also need to pay attention to and understand the following two points:

1. The time-consuming task should not be put into EDT, otherwise the application will become unable to respond. Because EDT is busy executing your time-consuming tasks, it does not have to worry about other GUI events. (No way. There are so many active standbys. It's hard for EDT to be a man or an EDT to be a man !)

 

2. If you access and modify GUI components in other threads, you must use SwingUtilities. invokeAndWait (), SwingUtilities. invokeLater ().

Both of them share the same role of placing the tasks to be executed into the Event Queue so that EDT allows the Event dispatching thread to call any code block in another thread.

 

So what is the difference between invokeLater () and invokeAndWait?

Literally speaking, public static void invokeLater (Runnable doRun) refers to the Runnable running experience in it which will be called and run later. The entire execution is asynchronous.

Public static void invokeAndWait (Runnable doRun) refers to the Runnable running experience defined in it, which calls and waits for the result to be returned, and is synchronized.

The following two examples show their differences:

(1)

Code
public class SwingDemoInvokeAndWait {
    public static void main(String[] argv) throws InterruptedException, InvocationTargetException {

        SwingUtilities.invokeAndWait(new Runnable() {

            @Override
            public void run() {
                constructUI();

            }
        });

        final Runnable doHelloWorld = new Runnable() {
            public void run() {

                System.out.println("Hello World on " + Thread.currentThread());

            }
        };

        Thread appThread = new Thread() {
            public void run() {
                try {
                    SwingUtilities.invokeAndWait(doHelloWorld);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("Finished on " + Thread.currentThread());
            }
        };
        appThread.start();

    }

    private static void constructUI() {
        JLabel bulletin = new JLabel("Hello,World!", JLabel.CENTER);

        JFrame frame = new JFrame("Bulletin");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(bulletin);
        frame.setSize(200, 150);
        frame.setVisible(true);
        bulletin.setForeground(Color.RED);

    }
}

Because doHelloWorld is executed in invokeAndWait, it will definitely wait for the doHelloWorld method to be executed and return, that is, "Hello World on" will be displayed before "Finished on.

(2)

Code
import java.awt.Color;
import java.lang.reflect.InvocationTargetException;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class SwingDemoInvokeLater {
    public static void main(String[] argv) throws InterruptedException, InvocationTargetException {


        final Runnable doHelloWorld = new Runnable() {
            public void run() {

                System.out.println("Hello World on " + Thread.currentThread());

            }
        };

        Thread appThread = new Thread() {
            public void run() {
                try {
                    SwingUtilities.invokeLater(doHelloWorld);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("Finished on " + Thread.currentThread()+",but this might well be displayed before the other message.");
            }
        };
        appThread.start();

    }

    private static void constructUI() {
        JLabel bulletin = new JLabel("Hello,World!", JLabel.CENTER);

        JFrame frame = new JFrame("Bulletin");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(bulletin);
        frame.setSize(200, 150);
        frame.setVisible(true);
        bulletin.setForeground(Color.RED);

    }
}

 

Because doHelloWorld is executed in invokeLater, "Finished on" may appear before other information, such as "Hello World On ".

 

 

 

 

 

 

References:

(1) Swing Threading and The event-dispatch thread

(2) Section 9.1. Why are GUIs Single-threaded? -Java Concurrency in Practice

(3) How to Use Threads-JFC Swing Tutorial, The: A Guide to Constructing GUIs, Second Edition

(4) A brief introduction to the Swing event distribution thread

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.