Before introducing the swing threading mechanism, let's introduce some background concepts.
Background concept
synchronous vs. asynchronous :
synchronization is when a program starts processing an event after initiating a request, waits for the result of processing, or waits for the request to complete before the program is blocked (block) until the request is completed.
asynchronous is returned immediately after the current program initiates the request, the current program does not immediately process the event and waits for the result of processing, and the request is processed at a later time.
serial vs. parallel :
serial refers to the number of requests to be processed in the order in which they are processed and the next one processed.
parallelism can be understood as concurrency, which refers to processing multiple requests at the same time (in fact, we can only theoretically understand this, especially if the number of CPUs is less than the number of threads, the true meaning of concurrency is nonexistent, the threads are only alternating intermittently (in the form of CPU time slices)).
Queue :
A queue is a linear data structure in which elements adhere to the "FIFO" principle. The queue is processed by processing the next one.
Threads in the Swing program
A swing program contains three types of threads: the initialization thread (Initial threads), the event dispatch thread (Dispatch thread), and the task thread (Worker thread).
Initialize thread : Each program has a main method, which is the entry for the program execution, which runs on the initialization thread. Initializes a thread to read the program parameters and initializes some of the objects. In many swing programs, the main purpose of the thread is to start the program's graphical user interface (GUI). Once the GUI is started, for most event-driven desktop programs, the initialization of the thread is over, and the control of the program is given to the UI.
Event Dispatch thread (EDT) : primarily responsible for drawing and updating GUI components and responding to user input. Each EDT is responsible for managing an event queue (EventQueue), each time the user requests for updates to the interface (including the keyboard, mouse, and so on) are queued to the event queue and wait for the EDT to be processed.
Task Thread : It is primarily responsible for the time-consuming tasks and input/output intensive operations that are not directly related to the interface, that is, any interference or delay in the handling of UI events should be done by the task thread. Note that the task thread is explicitly started by the Javax.swing.SwingWorker class.
EDT Thread considerations
One, any GUI requests must be handled by the EDT thread
The EDT thread puts all GUI component drawing and update requests and event requests into an event queue. Queue This data structure is also mentioned before, it is linear, "first-out". Therefore, through the mechanism of the event queue, the concurrent GUI requests can be converted into event queues, which are processed sequentially. This will ensure thread safety. So, while most swing APIs are not inherently thread-safe, swing ensures thread safety through the EDT threading and event queuing mechanisms.
Similarly, it is not recommended to directly access the UI components and their event handlers from other threads, which can compromise thread safety and may result in interface updates and drawing errors .
Ii. Adding GUI requests to the event queue of the EDT thread in non-EDT threads through the Invokelater and Invokeandwait methods
Sometimes it is necessary to call the swing API in a non-EDT thread to handle GUI requests, and according to the first note, obviously we cannot access the GUI components directly. At this point we can call both methods to add GUI requests to the event queue of the EDT thread.
For example: We have a Class A inherited from JFrame, how to properly start the GUI in the Main method? We know that the main method belongs to the initialization thread, which is the typical non-EDT thread to access the GUI component problem.
The error is initiated in the following way: New A ();
If you do this, it is equivalent to accessing the GUI component directly in a non-EDT thread, which destroys thread safety.
The correct starting mode is:
Swingutilities.invokelater (New Runnable () {
public void Run () {
Creategui ();
}
});
With the Invokelater and Invoke methods, GUI requests can be added to the event queue of the EDT thread from a non-EDT thread.
The difference between the two methods is thatInvokelater is asynchronous, and when the method is called, the method adds the GUI request to the event queue and returns directly. Invokeandwait is synchronous, and when the method is called, the method adds the GUI request to the event queue and blocks until the request is completed before it is returned.
Three, time-consuming operations should be placed in the task thread, starting the task thread through SwingWorker
The mechanism of the event queue for EDT, while ensuring thread safety, also introduces a new problem: assuming that a certain GUI request execution time in the event queue is very long, then due to the characteristics of the queue, subsequent GUI requests in the queue will be blocked. In the actual application, the performance is: Clicking on a button triggers a time-consuming task after the other components are unresponsive and must wait for the task to finish the interface to resume the response.
Let's test it with a simple program, a simple Swing applet. The Start button simulates writing data (time-consuming operation), and the display button is used to output the contents of the text box to the text display area. After the data is written, output "data write complete" in the text box. After clicking the Start button, I clicked the display button three times in a row without any response. After three seconds, the response results come out and three lines of "data write complete" are output in the text display area. The user experience is extremely poor.
The code is as follows:
PackageSwing;Importjava.awt.*;Importjava.awt.event.*;Importjavax.swing.*; Public classTestedt { Public Static voidCreategui () {JFrame frame=NewJFrame ("Swing threading Mechanism")); JTextField TF=NewJTextField ("Hello World"); JTextArea Ta=NewJTextArea (); Ta.seteditable (false); JButton B1=NewJButton ("Start"); JButton B2=NewJButton ("Display"); JPanel P1=NewJPanel (); JPanel P2=NewJPanel (); P1.setlayout (NewBorderLayout ()); P2.add (B1); P2.add (B2); P1.add (Ta,borderlayout.center); P1.add (Tf,borderlayout.north); P1.add (P2,borderlayout.south); Frame.setdefaultcloseoperation (Jframe.exit_on_close); Frame.getcontentpane (). Add (p1); Frame.pack (); Frame.setvisible (true); //Start button to begin writing data, this operation takes a long timeB1.addactionlistener (NewActionListener () {@Override Public voidactionperformed (ActionEvent e) {//simulating time-consuming write data operations with the thread sleep method Try{Thread.Sleep (3000); } Catch(interruptedexception E1) {e1.printstacktrace (); } tf.settext ("Data Write Complete"); } }); //The display button is used to output the information in the text box to the text display areaB2.addactionlistener (NewActionListener () { Public voidactionperformed (ActionEvent e) {ta.append (Tf.gettext ()+ "\ n"); } }); } //start the GUI in the right way Public Static voidMain (string[] args) {Swingutilities.invokelater (NewRunnable () { Public voidrun () {Creategui (); } }); }}
Taking into account user experience, you should use a separate task thread to perform time-consuming calculations or input-output-intensive tasks such as communicating with the database, accessing Web site resources, and reading and writing large data volumes.
Four, do not call the Invokeandwait method in the EDT thread
In non-EDT threads, calling the Invokeandwait method can be a good way to add GUI requests to the event queue of the EDT thread. However, if the method is called in the EDT thread, a deadlock occurs.
This is because if the Invokeandwait method is called in the EDT thread, and the GUI request is added to the event queue, the Invokeandwait method will wait until the EDT thread finishes executing the request in its own run method, depending on its characteristics. However, for queues, the default request is added to the trailer. The EDT thread is based on the location where the request was not reached because its current request, invokeandwait, has not been completed yet.
In short, the EDT thread must complete the method before it can complete the GUI request, but the GUI request must be completed before the method can be completed. So the two sides wait for each other, creating a deadlock.
Usage of the task thread
The task thread is called by the SwingWorker class that needs to be displayed.
The generic parameter <T,V> represents:T is the SwingWorker
result type of this and the method returned, and is the doInBackground
get
V
type used to hold the SwingWorker
intermediate result of this and the publish
process
method.
As the name implies, the Doinbackground () method of the class represents the method that executes in the background, which is done by the task thread, and is used to perform time-consuming operations, and the Done () method is the method that is called after the Doinbackground method executes and the contents of the method body are delivered to the EDT thread. Used to process GUI requests.
The usage of the task thread is still demonstrated in the previous example of the "Write Data" program.
The code is as follows:
PackageSwing;Importjava.awt.*;Importjava.awt.event.*;Importjavax.swing.*; Public classTestedt { Public Static voidCreategui () {JFrame frame=NewJFrame ("Swing threading Mechanism")); JTextField TF=NewJTextField ("Hello World"); JTextArea Ta=NewJTextArea (); Ta.seteditable (false); JButton B1=NewJButton ("Start"); JButton B2=NewJButton ("Display"); JPanel P1=NewJPanel (); JPanel P2=NewJPanel (); P1.setlayout (NewBorderLayout ()); P2.add (B1); P2.add (B2); P1.add (Ta,borderlayout.center); P1.add (Tf,borderlayout.north); P1.add (P2,borderlayout.south); Frame.setdefaultcloseoperation (Jframe.exit_on_close); Frame.getcontentpane (). Add (p1); Frame.pack (); Frame.setvisible (true); //Start button to begin writing data, this operation takes a long timeB1.addactionlistener (NewActionListener () {@Override Public voidactionperformed (ActionEvent e) {NewSwingworker<integer,void>(){ protectedInteger Doinbackground () {//Analog Write data this time consuming operation Try{Thread.Sleep (3000); } Catch(interruptedexception e) {e.printstacktrace (); } return1; } protected voidDone () {Tf.settext ("Data Write Complete"); }}.execute (); } }); //The display button is used to output the information in the text box to the text display areaB2.addactionlistener (NewActionListener () { Public voidactionperformed (ActionEvent e) {ta.append (Tf.gettext ()+ "\ n"); } }); } //start the GUI in the right way Public Static voidMain (string[] args) {Swingutilities.invokelater (NewRunnable () { Public voidrun () {Creategui (); } }); }}
The test results are: After clicking the Start button, other components still have a good response. After three seconds, the text box content is successfully displayed as "Data write complete."
To summarize, the swing threading mechanism has the following considerations:
1. All GUI requests must be completed by the EDT thread (for thread safety), and it is not recommended to access GUI components through non-EDT threads
2. Non-EDT threads deliver GUI requests to the EDT thread through the Invokelater and Invokeandwait methods.
3. Disable calling the Invokeandwait method in the EDT thread (causing a deadlock).
4. The time-consuming operation is performed by the task thread, and the start task thread is displayed through the SwingWorker class.
Over
Swing threading Mechanism