Author: Hans Muller, Kathy Walrath translation: Guo Xiaogang (foosleeper@163.net)
Originally from java.sun.com
This article about multithreading in Swing, published in April 1998. One month later, we published another article "
Use Swing Worker threads, which discusses this topic in depth. To better understand how many threads work in swing, we recommend that you look at these two articles.
Note: In September 2000 we modified this article and its examples to apply to a new version of SwingWorker class. This version of the SwingWorker class fixes some subtle thread bugs.
Swing API design goals are powerful, flexible and easy to use. In particular, we hope to make programmers to easily establish new Swing components, whether it is from headstream or by extending some of our components.
For this purpose, we do not ask Swing components to support multi-threaded access. Instead, we send requests to the component and perform requests in a single thread.
This article discusses threads and swing components. The purpose is not only to help you use the Swing API in a thread safe manner, but also explains why we choose the thread solution now.
This article includes the following:
SLR Rule: Swing thread can only be accessed by one thread at the same time. In general, this thread is event-dispatching thread. Exceptions to the rules: Some operations are guaranteed to be threaded. Event distribution: If you need to access the UI from a place handle or draw code, you can use the invokelater () or invokeAndwait () method of the Swingutilities class. Create a thread: If you need to create a thread-such as working for some cost-consuming capacity or affected by I / O capabilities - you can use a thread tool class such as SwingWorker or Timer. Why do we implement Swing: We use some background information about Swing threads to end this article.
Swing rules are:
Once the SWING component is now a realized, all code that may affect or depend on the component status should be executed in the event dispatch.
This rule may sound a bit scary, but for many simple programs, you can not worry about thread problems. Before we write Swing code, let us first define two terms: realized and event distribution threads (event-dispatching thread).
It is also possible to form a Paint () method that is already or may be called. A SWING component as a top window will be added when the following method is called: setvisible (true), show () or (possibly surprised) Pack (). When a window is already chemically, all components therebet are already chemically. Another way to develop a component is to put it into an existing container. You will see some examples of the components later.
The event dispatching thread is a thread that performs drawing and event processing. For example, the Paint () and an ActionPerformed () method will automatically be executed in the event dispatch. Another way to put the code in the event dispatching process is the invokelater () method of the Swingutilities class.
All code that may affect a dedicated Swing component must be executed in an event dispatch. But this rule has some exceptions:
Some methods are thread safety: In the Swing API document, thread security methods are marked with the following text: This method is thread Safe, Although Most Swing Methods Are Not. (This method is thread safe, although most swing methods No.) The GUI of an application can often build and display in the main thread: The following typical code is safe, as long as there is no (swing or other) component is now chemical: public class myapplication {public static void main (String [ ] Args) {jframe f = new jframe ("labels"); // Add each component // to the main frame ... f.pack (); f.show (); // Don't do any GUI work ...} The code shown above is running in the "main" thread. The call to f.PACK () makes the components below JFrames have been chemically. This means that f.show () call is unsafe and should be executed in the event dispatching process. Despite this, as long as the program does not have a way you see the GUI, JFRAME, or the components inside it almost impossible to receive a PAINT () call before f .Show () returns. Because there is no longer any GUI code after f.show (), all GUI work is transferred from the main thread to the event distribution thread, so the code discussed earlier is actually threaded.
The GUI of an applet can be constructed and displayed in the init () method: existing browsers do not draw it before an applet's init () and start () methods are called. Thus, constructing the GUI is secure in an init () method of an applet, as long as you do not call the show () or setvisible method for an object in the applet. By the way, if the SWING component is used in the applet, you must implement subclasses for japplets. Also, the components should be added to the JApplet Content Pane, not directly to the Japplet. For any applet, you should not perform the initialization operation at the time of the init () or start () method; and should start a thread to perform the fee. The following JComponent methods are secure and can be called from any thread: repaint (), revALIDATE (), and invalidate (). The repaint () and revALIDATE () methods are queued for the event distribution thread and call the Paint () and validate () methods separately. The invalidate () method only tag a component and all of its direct ancestors only when you need to confirm. The listener list can be modified by any thread: call addListenertypelistener () and removelistenertypelistener () methods are always secure. Adding / deleting an addition / deletion operation for the listener list does not have any impact on the events in progress.
Note: The important difference between the RevalIdate () and the old validate () method is that revAlidate () caches the request and combines a validate () call. This is similar to the repaint () cache and combines the draw request.
Most initialized GUI work naturally happened in an event distribution thread. Once GUI is visible, most programs are driven by events, such as buttons, or mouse clicks, which always processed in the event dispatching.
However, there are always programs that need to perform some non-event-driven GUI work after GUI is visible. such as:
Programs that become a long-term initialization operation need to be used before it is available: This type of program should usually display the GUI during initialization, then update or change the GUI. The initialization process should not be carried out in an event dispatch; otherwise, the redraw assembly and event distribution will stop. Despite this, after initialization, the GUI's update / change should still be carried out in an event dispatch, and the reason is thread security. You must update the GUI program in response to non-AWT events: For example, imagine a server program to get a request from programs that might run on other machines. These requests may arrive at any time and will cause the server to call the server in some possible unknown threads. How do this method call to update the GUI? Execute the GUI update code in the event dispatch. The Swingutilities class provides two ways to help you execute the code in the event delivery line:
Invokelater (): Requires some code in the event dispatching process. This method will return immediately and will not wait for the code to complete. InvokeAndwait (): Behavior is similar to invokelater (), except for this method to wait for the code to execute. In general, you can replace this method with invokelater ().
Here are some examples of using these APIs. Please also see "The Java Tutorial" ""
Bingo EXAMPLE, especially the following classes:
CardWindow,
ControlPane,
Player and
OveralllStatuspane.
Using the invokelater () method
You can call the InvokeLater () method from any thread to request the event dispatch running a specific code. You must put the code you want to run into a Run () method of a runnable object and set this RunNable object to the parameter of InvokeLater (). The invokelater () method will return immediately, and the event is sent to send the specified code. This is an example of using an invokelater () method:
Runnable DOWORKRunnable =
New runnable () {
public
Void Run () {DOWORK ();
}
Swingutilities.Invokelater (DOWORKRunnable);
Using invokeAndwait () method
The InvokeAther () method and the invokelater () method are very similar, in addition to the incident dispatched process for the invokeAit () method to return to the specified code. In the case of possible, you should try to use Invokelater () to replace InvokeAndWait (). If you really want to use INVOKEANDWAIT (), make sure the thread calling the invokeAndWait () does not hold the lock that may be needed during the call.
This is an example of using invokeAndwait ():
Void showhellotheredialog ()
Throws exception {
Runnable showmodaldialog =
New
Runnable () {
public
Void Run () {
JOPTIONPANE.SHOWMESSAGEDIALOG
MymaInframe,
"Hello there");
}
}
Swingutilities.invokeAndwait
ShowModalDialog;
}
Similarly, suppose a thread needs to access the status of the GUI, such as the content of the text domain, it may be like this:
Void PrintTextField ()
Throws exception {
Final String [] mystrings =
NEW STRING [2];
Runnable gettextfieldtext = new runnable () {
public
Void Run () {
MyStrings [0] =
TextField0.getText ();
MyStrings [1] =
TextField1.getText ();
}
}
Swingutilities.invokeAndwait
GetTextFieldText;
System.out.println (MyStrings [0]
" Mystrings [1]);
}
If you can avoid using threads, it is best to do this. Threads may be difficult to use and make the program's Debug more difficult. In general, the thread is unnecessary to work in strict sense, such as updates to component properties.
Anyway, sometimes the thread is necessary. The following cases are some typical situations of using threads:
Perform a fee-time task without having to send events to lock. Examples include the case where a large amount of calculations will result in a large number of cases (such as initialization), and is blocked for the network or disk I / O. An operation is repeatedly performed, usually a predetermined time period between two operation intervals. Wait a message from the customer.
You can use two classes to help you implement threads:
SwingWorker: Create a background thread to perform a fee. Timer: Create a thread to perform some code multiple times, execute the delay in inter-interval user definitions.
Use SwingWorker class
SwingWorker class
SwingWorker.java is implemented, this class is not included in any release of Java, so you must download it separately.
The SwingWorker class made all the dirty work required to implement a background thread. Although many programs do not need the background thread, the background thread is still very useful when the operation is performed, it can improve the performance of the program.
SwingWorker's get () method. Here's an example of useing swingworker:
To use a SwingWorker class, you first want to implement one of its subclasses. In the subclass, you must implement the construct () method also contains your long operation. When you instantiate SwingWorker's subclasses, SwingWorker creates a thread but does not start it. You want to call your SwingWorker object's start () method to start the thread, then the start () method calls your construct () method. When you need the object returned by the construct () method, you can call the Get () method of the SwingWorker class. This is an example of using the SwingWorker class:
...
// In the main method:
Final SwingWorker Worker =
New swingworker () {
Public Object construct () {
Return
New
ExpensiveDialogComponent ();
}
}
Worker.start ();
...
// In the action event processing method:
JOPTIONPANE.SHOWMESSAGEDIALOG
(f, worker.get ());
When the main () method of the program calls the start () method, SwingWorker launches a new thread to instantiate the ExpensiveDialogComponent. The main () method also constructs a GUI consisting of a window and a button.
When the user clicks the button, the program will block, if necessary, block the ExpensiveDialogComponent creation completion. Then the program displays a mode dialog containing the ExpensiveDialogComponent. You can find the entire program at MyApplication.java.
Use the Timer class
The Timer class performs or performs an action multiple times by an ActionListener. When you create a timer, you can specify the frequency execution execution, and you can specify the listener of the timer's action event. When the timer is started, the action listener's actionPerformed () method is called (multiple) to perform the operation.
The ActionPerformed () method defined by the timer action listener will call in the event dispatch. This means you don't have to use the InvokeLater () method.
This is an example of using the TIMER class to achieve an animation cycle:
public
Class AnimatorApplicationTIMER
Extends jframe
IMPLEMENTS
ActionListener {
...
/ / Define instance variables here
Timer Timer;
Public AnimatorApplicationTIMER (...) {
...
// Create a timer
// Call this object Action Handler.
Timer =
New Timer (Delay,
THIS);
Timer.setInitialDelay (0);
Timer.Setcoalesce (
True);
...
}
public
Void startAnch () {
IF (frozen) {
// do nothing. Application request
// Stop transform image.
}
Else {
// Start (or restart) animation!
Timer.Start ();
}
}
public
Void stopanimation () {
// Stop the animation thread.
Timer.stop ();
}
public
Void ActionPerformed
(ActionEvent E) {
// Go to the next frame of animation.
Framenumber ;
// Display.
Repaint ();
}
...
}
Perform all user interface code in a thread has some advantages:
Components Developers don't have to understand thread programming: All components in the toolkit in ViewPoint and TRestle must fully support multi-thread access, making it very difficult to expand, especially for developers who are not proficient in thread programming. Recently, some of the toolkits such as SubARCTIC and IFC use and Swing a similar design. The event is distributed in a predictable order: InvokeLater () queued RunNable object sent from the mouse and keyboard event, timer event, and drawing the same queue. In some of the tool packs that completely support multi-thread access, the change in components is changed by incomplete thread scheduling programs to the event processing. This makes comprehensive testing difficulties or even impossible. Lower price: Try to be careful to lock the toolkit of the critical area to spend the feet time and space in the locked management. Whenever a method in which a method implemented in a customer code (such as any public and protected methods in the public class), the kit must save its status and release all locks so that the customer code can be Get the lock. When the control is retracted to the toolkit, the toolkit must restrained its lock and restore the status. All applications have to afford this price, even if most applications do not need to access concurrent access to GUI.
This is the description of the SubARCTIC Java Toolkit's author to support multi-threaded access in the toolkit:
Our basic creed is that when designing and building multi-threaded applications, especially those including GUI components, must be guaranteed to be extremely careful. The use of threads may be very deceptive. In many cases, they behave greatly and simplified, making it possible to design "simple autonomous entities who focus on single tasks". In some cases they indeed simplify design and encoding. However, in almost all cases, they have greatly increased difficulties in debugging, testing, and maintenance, even impossible. Regardless of the training of most programmers, their experience and practice, or we use them to help themselves, they are not able to deal with non-decisive. For example, a comprehensive test (this is always difficult) is almost impossible at BUG depends on time. Especially for Java, a program is running on the operating system platform of many different types of machines, and each program must work normally under preemptive and non-robbery schedules. Due to these inherent difficulties, we advise you to think about whether it is necessary to use threads. Despite this, in some cases use threads are necessary (or by other software package strength), SubARCTIC provides a thread security access mechanism. This chapter discusses this mechanism and how to operate interactive trees in a stand-alone thread.
The thread safety mechanism they said is very similar to the InvokeLater () and invokeAndwait () methods provided by the Swingutilities class.