Thread safety selection and swing[z in Java development]
Source: Internet
Author: User
The Security Swing API is designed to be powerful, flexible, and easy to use. In particular, we want to make it easy for programmers to create new swing components, either from scratch or by extending some of the components we provide.
For this purpose, we do not require swing components to support multithreaded access. Instead, we send the request to the component and execute the request on a single thread.
This article discusses threads and swing components. The goal is not only to help you use the swing API in a thread-safe way, but also to explain why we chose the threading scheme now.
This article includes the following:
Single-threaded rule: Swing threads can only be accessed by one thread at a time. Typically, this thread is an event-distributing thread (event-dispatching thread).
Exceptions to the rule: some operations are guaranteed to be thread-safe.
Event Distribution: If you need to access the UI outside of event handling (event-handling) or drawing code, you can use the Invokelater () or invokeandwait () method of the Swingutilities class.
To create a thread: If you need to create a thread--for example, to work with a lot of computational power or I/O limitations--You can use a threading tool class such as SwingWorker or a timer.
Why we implement swing this way: We'll end this article with some background information about swing's thread safety.
The rules of Swing are:
Once the swing component is materialized (realized), all code that may affect or depend on the component state should be executed in the event-issuing thread.
This rule may sound a bit scary, but for many simple programs, you don't have to worry about threading problems. Before we go into how to write swing code, let's define two terms: materialized (realized) and event-Distributing threads (event-dispatching thread).
Materialized means that the paint () method of the build has been or may be invoked. A swing component that acts as a top-level window will be materialized when the following methods are invoked: SetVisible (True), show (), or (perhaps surprise you) pack (). When a window is materialized, it contains all the components that are present. Another way to present a component is to put it into a container that is already in the process of being materialized. You'll see some examples of how the components are being materialized later.
The event-issuing thread is the thread that executes the drawing and event handling. For example, the paint () and actionperformed () methods are automatically executed in the event-distributing thread. Another way to put code into an event-distributing thread is to use the Invokelater () method of the Swingutilities class.
All code that might affect an already existing swing component must be executed in the event-issuing thread. But there are some exceptions to this rule:
Some methods are thread-safe: In the documentation for the Swing API, thread-safe methods are marked with the following text:
This is thread safe, although most Swing methods are.
(This method is thread-safe, although most swing methods are not.) )
The GUI for an application can often be built and displayed in the main thread: The following typical code is safe, as long as no components (swing or other) are materialized:
public class MyApplication
{
public static void Main (string[] args)
{
JFrame f = new JFrame ("Labels"); Here will be the components
Add to Main frame ...
F.pack ();
F.show ();
Do not do any GUI work ...
}
}
All of the code shown above runs in the "main" thread. The invocation of the F.pack () makes the components below JFrame to be materialized. This means that the f.show () call is unsafe and should be performed in the event-issuing thread. Nevertheless, it is almost impossible for a program to receive a paint () call before the F.show () is returned, as long as it does not have a visible gui,jframe or a component inside it. Since there is no GUI code after the F.show () call, all GUI work is transferred from the main thread to the event-issuing thread, so the code discussed above is actually thread-safe.
The GUI for an applet can be constructed and displayed in the Init () method: None of the existing browsers will draw it before the Init () and Start () methods of an applet are invoked. Thus, it is safe to construct the GUI in an applet's init () method, as long as you do not invoke the show () or setvisible (True) method on objects in the applet.
Incidentally, if the swing component is used in the applet, it must be implemented as a japplet subclass. Also, the component should be added to the JApplet Contents pane (content pane) instead of adding directly to JApplet. You should not perform time-consuming initialization in the init () or Start () method for any applets, and you should start a thread to perform time-consuming tasks.
The following jcomponent methods are safe and can be invoked from any thread: repaint (), revalidate (), and invalidate (). The repaint () and Revalidate () methods queue the request for an event-issuing thread and invoke the paint () and validate () methods, respectively. The invalidate () method only marks a component and all its direct ancestors when a confirmation is required.
The listener list can be modified by any thread: calling the Addlistenertypelistener () and Removelistenertypelistener () methods is always safe. Add/Remove to listener list does not have any effect on the distribution of events in progress.
Note: The important difference between the revalidate () and the old Validate () method is that revalidate () caches the request and combines it into a validate () call. This is similar to repaint () caching and combining drawing requests.
Most of the initialized GUI work naturally occurs in the event-distributing thread. Once the GUI becomes visible, most programs are event-driven, such as button actions or mouse clicks, which are always handled in the event-distribution thread.
However, there are always programs that need to perform some non event-driven GUI work after the GUI becomes visible. Like what:
A program that requires lengthy initialization before it is available: Such programs should typically display the GUI during initialization and then update or change the GUI. The initialization process should not occur in the event-issuing thread, otherwise the redraw component and event distribution will stop. However, after initialization, the update/change of the GUI should still be done in the event-issuing thread, citing thread safety.
Programs that must respond to non-AWT events to update the GUI: for example, imagine a server program getting a request from a program that might run on another machine. These requests can arrive at any point in time and cause a method call to the server in some potentially unknown threads. How does this method call update the GUI? Executes the GUI update code in the event distribution thread.
The Swingutilities class provides two ways to help you execute code in an event-issuing thread:
Invokelater (): Requires some code to be executed in the event-distributing thread. This method returns immediately and does not wait for the code to finish executing.
Invokeandwait (): The behavior is similar to Invokelater (), except that this method waits for the code to finish executing. Generally, you can replace this method with Invokelater ().
Here are some examples of using these APIs. See also "BINGO example" in the Java Tutorial, especially in the following categories: Cardwindow, Controlpane, player, and Overallstatuspane.
Using the Invokelater () method
You can call the Invokelater () method from any thread to request an event-issuing thread to run a particular code. You have to put the code you want to run into a Runnable object's run () method and set this Runnable object as an argument to Invokelater (). The Invokelater () method returns immediately without waiting for the event to be distributed by the thread to execute the specified code. This is an example of using the Invokelater () method:
Runnable doworkrunnable = new Runnable ()
{
public void Run ()
{
DoWork ();
}
};
Swingutilities.invokelater (doworkrunnable);
Using the Invokeandwait () method
The Invokeandwait () method is very similar to the Invokelater () method, except that the Invokeandwait () method performs the specified code before the event-issuing thread executes. Where possible, you should try to use Invokelater () instead of invokeandwait (). If you really want to use invokeandwait (), make sure that the thread that calls Invokeandwait () does not hold a lock that any other thread might need 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, assuming that a thread needs to access the state of the GUI, such as the contents of a text field, its code might look 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's best to do so. Threads can be difficult to use and make debug of a program more difficult. In general, threads are unnecessary for working with a strictly GUI, such as updating component properties.
At any point, threads are sometimes necessary. The following are some typical cases of using threads:
Perform a time-consuming task without having to distribute the event to a thread lock. Examples include performing a large number of computations, causing a large number of classes to be loaded (such as initialization), and blocking the network or disk I/O.
Performs an operation repeatedly, usually between two operations and a predetermined period of time.
To wait for a message from the customer.
You can use two classes to help you implement threads:
SwingWorker: Create a background thread to perform time-consuming operations.
Timer: Create a thread to execute or execute some code more than once, with a user-defined delay between two executions.
Using the SwingWorker class
The SwingWorker class is implemented in Swingworker.java, and this class is not included in any of the distributions in Java, so you must download it separately.
The SwingWorker class does all the dirty work required to implement a background thread. Although many programs do not require background threading, background threads are still useful when performing time-consuming operations that can improve the performance of the program.
SwingWorker ' s Get () method. Here's an example of using SwingWorker:
To use the SwingWorker class, you first want to implement one of its subclasses. In subclasses, you must implement the construct () method and include your long time operation. When you instantiate a SwingWorker subclass, SwingWorker creates a thread but does not start it. You will call your SwingWorker object's start () method to start the thread, and then the start () method will call your construct () method. When you need an 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 handling method:
Joptionpane.showmessagedialog (F, Worker.get ());
When the program's main () method calls the Start () method, SwingWorker starts a new thread to instantiate the expensivedialogcomponent. The main () method also constructs a GUI composed of a window and a button.
When the user clicks on the button, the program blocks and, if necessary, blocks to the expensivedialogcomponent creation complete. The program then displays a modal dialog box that contains Expensivedialogcomponent. You can find the whole program in Myapplication.java.
Using the Timer class
The Timer class executes or performs an operation multiple times through a actionlistener. You can specify how often the operation executes when you create the timer, and you can specify the listener (action Listener) of the timer's action event. After the timer is started, the action Listener's actionperformed () method is invoked (multiple times) to perform the action.
The actionperformed () method defined by the Timer Action Listener (Action Listener) is invoked in the event-issuing thread. This means that you do not have to use the Invokelater () method in it.
This is an example of using the Timer class to implement an animation loop:
public class Animatorapplicationtimer
Extends JFrame implements ActionListener {
.//Define instance variables here
Timer timer;
Public Animatorapplicationtimer (...) {
..//Create a timer to
To invoke this object action handler.
Timer = new Timer (delay, this);
Timer.setinitialdelay (0);
Timer.setcoalesce (TRUE);
...
}
public void Startanimation () {
if (frozen) {
Don't do anything. Upon user's request
Stops the transform image.
} else {
Start (or restart) the animation!
Timer.start ();
}
}
public void StopAnimation () {
Stop the animation thread.
Timer.stop ();
}
public void actionperformed (ActionEvent e)
{
Go to the next frame of the animation.
framenumber++;
Show.
Repaint ();
}
...
}
Executing all of the user interface code in one thread has some advantages:
Component developers do not have to have a deep understanding of threading: all components in such toolkits as viewpoint and trestle must fully support multithreaded access, making scaling difficult, especially for developers who are not proficient in threading programming. Some of the most recent toolkits, such as subarctic and IFC, have similar designs to swing.
Events are distributed in a predictable order: Invokelater () The queued runnable objects are distributed from the mouse and keyboard events, timer events, and the same queue of drawing requests. In a toolkit where some components fully support multithreaded access, component changes are interspersed with the vagaries of the thread scheduler into the event-handling process. This makes full-scale testing difficult or impossible.
Lower cost: Try to lock the critical section of the toolkit carefully to spend time and space on the lock management. Whenever a method that might be implemented in client code is invoked in a toolkit (such as any public and protected method in the public class), the toolkit saves its state and releases all locks so that the client code can acquire locks if necessary. When control is handed back to the toolkit, the toolkit must regain its lock and restore status. All applications have to bear the cost, even if most applications do not require concurrent access to the GUI.
This is Subarctic Java Toolkit's author's description of the problem supporting multithreaded access in the toolkit:
Our basic tenet is to be extremely careful when designing and building multithreaded applications, especially those that include GUI components. The use of threads can be deceptive. In many cases, they appear to be very well simplified, making it possible to design "simple autonomous entities focused on a single task". In some cases they did simplify design and coding. In almost all cases, however, they make debugging, testing, and maintenance more difficult or impossible. No matter how many programmers are trained, their experiences and practices, or the tools we use to help ourselves, we are not able to deal with the non determinism. For example, comprehensive testing (which is always difficult) is almost impossible when a bug relies on time. Especially for Java, a program runs on the operating system platform of many different types of machines, and each program must work under preemptive and non preemptive scheduling.
As a result of these inherent difficulties, we urge you to think twice whether it is absolutely necessary to use the thread. However, in some cases the use of threads is necessary (or imposed by other packages), so subarctic provides a thread-safe access mechanism. This chapter discusses this mechanism and how to safely manipulate the interactive tree in a separate thread.
The thread-safe mechanism they call is very similar to the Invokelater () and invokeandwait () methods provided by the Swingutilities class.
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.