Swing thread final discussion - use asynchronous model

zhaozj2021-02-16  68

Originally from java.sun.com

Author: Joseph Bowbeer

This article does not belong to any series, but it is

The third article published in The Swing Connection About Using Threads in Swing.

First article

"Thread and SWING" explains Swing single-threaded rules. This article can now be found in The Swing Connection Archive.

Second article

"Use the Swing Worker Thread" to demonstrate how to use the SwingWorker thread tool class. It can also be found in the archive.

This article describes the revised SwingWorker class and demonstrates the model-based component, such as JTABLE and JTREE, using threads simultaneously.

To understand the materials presenting this article, familiar with SwingWorker and JTABLE and JTREE components will help. You can

An article about JTABLE and JTREE is found in the archive index.

This paper is divided into the following main parts:

Introduction and review

Dynamic tree

Remote tree

SwingWorker Revision

download

in conclusion

Reference

About author

-------------------------------------------------- -------------------------

Introduction and review

Before drilling trees, tables, and asynchronous models, I first reviewed Single-Thread Rule and tested its meaning.

Swing's single-threading rule is that Swing components can only be accessed by one thread at a moment. This rule is valid for gets and sets, and "a thread" usually refers to event distribution threads.

SLR rules apply to the UI component is very commensuer, because the UI component is often used in single-threaded manner, and most acts are initiated by the user. Components to build threads are difficult and long-tedious: if it is avoided, it is preferred. But except for its benefits, single thread rules have more meaning.

All events of SWING components are sent and received in event-dispatch threads, in addition to this only complied with single threaded rules. For example, Property-Change Events should be sent in the event dispatching thread, and model change events should be received in the event dispatching.

For model-based components such as JTABLE and JTREE, single thread rules mean that they can only access the model itself in the event dispatching. For this reason, the method in the model must be implemented soon and must not block, otherwise the entire user interface will be slow.

But imagine that you have a JTREE with Treemodel to access a remote server? You will find that when the server is unavailable or too busy, your TreeModel's call will block and make the entire user interface frozen. What can you do to improve the responsiveness of the interface?

Again, have a JTABLE with TABLEMODEL to manage a device on the network? You will find that when the managed equipment is busy or the network is crowded, the interface becomes slow. what should you do?

These difficulties are in summoning threads. When the demand has emerged, we still have several ways to use threads in Swing, although there is a single threaded rule.

This article shows two ways to use threads to access slow, remote, or other asynchronous models and display how to use in JTREE and JTABLE components. (The model that is not only sent by the event is called "asynchronous" model.)

-------------------------------------------------- ---------------------------

Dynamic tree

Suppose you have a JTree with TreeModel to access the remote server, but the server is slow or unreliable, what should you do? DynamICTree demonstrates how to dynamically expand the JTree node using the background thread.

Figure 1 is a DynamiCTree being processed in the processing node.

figure 1

Split model (split-model) design

DynamicTree is based on a split model design (Split-Model Design). In this design, the real model is an asynchronous model that may be slow or unreliable. The JTree model uses a standard synchronization model to maintain a true model of Snapshot. (Asynchronous models may be in remote servers, I usually referred to as remote models for this reason, and I call the model of the SWING component as a local model.)

The use of local models to image or cache the remote model helps provide a SWING component that is reliable at all times. But a shortcoming of this method is also the necessary cost is that the model data has to be repeated. Another problem is that the two models are not always synchronized, and they have to be coordinated with each other.

Update when expanding: Dynamic browsing

One coordination method between the model is to update the local model only when data is required, not before this. This technique is useful when the remote model is slow or large, but this technical requirement model is basically static. DynamicTree uses this method to browse a slow static tree model.

DynamicTree is a unniffered root node, and there is an Expansion Listener waiting for user input to expand the node. When the node is expanded, expand the auditor to launch a SwingWorker thread. This Worker's construct () method accesses the remote model and returns a new child node. Then Worker's finished () method will execute in the event dispatch, add the child node to the local model.

For simplicity, only one worker is allowed at the same time. If any node is folded, any Worker currently will be interrupted. (The program does not check if the folded node is the ancestor of the Node that worker is being expanded.)

Execution order

Figure 2 shows the process of starting the node. The execution process starts and ends in the event distribution thread on the left. SwingWorker starts in the Worker thread on the right side of the figure. The solid arrow is a method call, the dotted arrow is returned, and the half arrow is an asynchronous request.

Figure 2 DynamICTree execution sequence diagram

The remainder of this section will discuss the structure and implementation. You can also skip the following remote model demo. The following "Download" section explains how to download and run the presentation.

achieve

Figure 3 is a schematic class structure diagram.

Figure 3 Dynamictree

The local model is a DefaultTreeModel with a defaultmutabletreenode node. The node must be variable so that the child node can be dynamically added. The UserObject domain of variable nodes can be used to point to the remote model.

TreenodeFactory

The remote model implements the TreenodeFactory interface:

public

Interface TreenodeFactory {

Defaultmutabletreenode [] CreateChildren (Object UserObject)

Throws Exception;

}

CreateChildren () is called in the Worker thread. Similar to most asynchronous and remote methods, it will throw an exception (generally a remoteexception or interruptedException). The UserObject parameter is a recently expanded node to refer to a link to the remote model. One returns an array including all child nodes is more efficient than alone, and can avoid the face of the face failure.

At initialization, each child node is set to be set by the allowschildren property and a link to the remote model. (If the remote node is the leaves node, the AllowsChildren property is set to false; otherwise, AllowSchildren is set to True to indicate that the node can be expanded.) DefaultTreenodeFactory is an Adapter (please refer to GOF "Design Patterns"). It uses any TreeModel to connect to the TreenodeFactory interface. The default tree model is used in the demo program. Some comments in the main method demonstrate how to install a FileSystemNodeFactory. SlowtreenodeFactory is a packaging class that demonstrates; it is inserted into a random delay in run.

future job

I have tried to keep DynamicTree simple. There is no other content in the node in addition to the node. In the case where the content is required in the node, if you can load the content asynchronously, it will be better, such as you may use a tree selection listener to initialize the loading process.

The remote performance presentation program in the next section will be more practical.

-------------------------------------------------- -----------------------------

Remote table

Suppose you have a JTable with TableModel to manage a remote device, but the interface is slow when the device is busy, what should you do?

The following remote spending programs use the background thread and asynchronous callbacks to display or modify a remote table model.

Figure 4 is a remote table editor being sent to the server a new value. Unprocessed cells remain yellow before the update is complete.

Figure 4

RemoteTable bean

Remote performances are implemented with RMI, which consists of one server and two clients (an editor and a viewer). The viewer is actually a editor that is forbidden to edit the function.

The client uses a RemoteTable component bean, and RemoteTable is a subclass of JTable designed to work with the remote table model. The editor shown in Figure 4 is constructed of a RemoteTable component, a status tag, a simple activity meter (lower right corner), and some code for locating the server.

Update when notification

DynamICTree updates its local model only when data is required, in this regard, the RemoteTable component gets all the data at the beginning and listens to changes. The technique based on notification-based can work with the dynamic model and works well in the model.

Modify driver notification for cells. When the user completes the editing of the cell, RemoteTable labeled the edited cells as unprocessed (yellow highlighting) and arranges a SwingWorker task. The WOKER's construct () method sends a new value to the remote model.

When the remote model receives a new value, it notifies the listener. The unique function of the Worker's finished () method is to confirm that the task has been completed; after the notification from the remote model is accepted and processed, the yellow unprocessed cells change back to the normal cell.

Task queue

RemoteTable scheders its SwingWorker task with a Queuedexecutor, QueuedExecutor executes all tasks in a single thread. (Queuedexecutor is part of the DOUG LEA's Util.Concurrent package, see the "Reference" section later.) The remote model notifies its listener with the RMI callback operation.

In order to support visual feedback, RemoteTable sends a Task event to the registered Task listener. When the task enters schedule, the taskstarted () of the listener is called, and taskended () is called when the task is completed. The client demo program uses these events to start or stop a small image and update the status. Execution order

Figure 5 shows a cell update process. The start and end of the execution process is located on the left event distribution thread. The SwingWorker task is executed in the thread of the EXECUTOR on the right. The execution process of the Worker's finished () method is not expressed.

Figure 5 RemoteTable execution sequence diagram

simplify

Simple, the remote model does not protect the editing of mutual conflict. So there can be one editor at the same time. (Concurrent editing can be implemented with the method of adding request ID (Request IDs).)

Another simplified decision made is that the client and server must be negotiated with the column structure of the table in advance. In other words, the server-based client provides row data, and the client must already know what the table they have to handle. The client used the client to pre-define the names and classes of each column in advance to determine which cell can be edited. (In the demo, the first two columns are not editable.)

The remainder of this section describes the structure and implementation. If you don't want to know the revised SwingWorker used in this demo, you can jump over. "Download" section explains how to download and run this demo.

achieve

Figure 6 is a schematic class configuration diagram.

Figure 6 RemoteTable

The remote model implements the RemoteTableModel interface, this interface and AbstractTableModel are very similar, except that all of it will throw an exception. To launch a client, the remote table model sends a full update event to the client's registered listener.

RemoteTableModeLadapter comes with any TableModel to a RemoteTableModel. The table model in the demo procedure is taken from the Java Tutorial, but some delays are inserted to simulate the actual situation. The remote table model event contains the value of the updated cell.

RemoteTable components use a defaultRemoteTableModelliStener to accept callbacks from the remote model. This listener updates the local model in the event dispatching process. Because the remote model may notify inform or delete some rows, the listener requires the local model to support insert and delete operations, and DefaultTableModel satisfies this requirement.

-------------------------------------------------- -----------------------------

SwingWorker Revision

The demo program performs a fee when it costs in the background, and then updates the UI.

The SwingWorker used by this demonstration is based on the SwingWorker class proposed in the SwingWorker thread, but re-implements it to correct a rapid condition, add timeout support, and improve the exception handling.

This new implementation is also based on the Futureresult class of the Doug LEA's Util.Concurrent package (see "Reference" section). Since the work done by Futureresult, the implementation of the SwingWorker class is simple and flexible.

The remaining parts of this section describe the details of the implementation in more detail, please continue to look down or jump directly to the back download source.

Runnable Futureresult

Futureresult, as its name is implicit, it is used to maintain a result of a move. It is designed to use a Callable, and Callable is a Runnable action that will return the result:

public

Interface callable {

Object Call ()

Throws Exception;

The new SwingWorker is a runnable futureresult. At runtime, it sets the result into a return value of construct () and then calls the finished () method in the event dispatch. (Note: SwingWorker is an abstract class; you want to type it and implement construct () and finished ().)

The following code comes from the RUN () method of SwingWorker:

CALLABLE FUNCTION =

NEW CALLABLE () {

Public Object Call ()

Throws exception {

Return construct ();

}

}

Runnable Dofinished =

New runnable () {

public

Void Run () {

Finished ();

}

}

Setter (function) .run ();

Swingutilities.Invokelater (Dofinished);

The first paragraph converts construct () into a Callable action, and the second paragraph converts Finished () into the Dofinished as a runnable. Then setter is run, and Dofinished is called.

Setter (Function)

The material that is missing is setter (function). It creates a engraved runnable. At runtime, this runnable calls the Function specified by the parameter, and then returns the result settings. Below is the code from the Futureresult:

Public Runnable Setter

Final Callable function) {

Return

New runnable () {

public

Void Run () {

Try {

set (function.call ());

}

Catch (throwable ex) {

SETEXCEPTION (EX);

}

}

}

}

Pay attention to the protection of the Try-Catch block. If construct () throws anything (Exception, Error, etc.), will be captured and recorded.

Don't grab: first construct, then start

Call Start () to launch the worker thread. This is an important difference between the revised SwingWorker and the original version.

In the original version, the SwingWorker () constructor automatically starts threads, which brings a risk of competition for threads and sub-constructor: When the SwingWorker () constructor has launched threads, while the subclass constructor is also not complete. Method is to construct SwingWorker first, then call START ().

By the way, RemoteTable does not call Start (). Correctly, SwingWorker is executed as a runnable by Queuedexecutor.

Overtime support

The new SwingWorker supports timeout, which is implemented by overriding the gettimeout () method has returned a non-zero value. When the timeout time, the Worker thread will be interrupted.

If you want to view an example of using the timeout, see how the comment version gettimeout () method and DynamICTree handle TimeOutException.

The timeout function is implemented with timedcallable, which uses Futureresult's TimEt () method.

Enhanced abnormal treatment

Anything thrown by the construct () method will be recorded. In addition to death cycles and deadlocks, new abnormalities ensure that SwingWorker is "ready". That is to say, it either gives a correct result or gives an exception. The following GET () method is used to take the result. This method inherits from Futureresult:

Public Object GET ()

Throws InvocationTargeTexception, InterruptedException

If construct () throws an Exception, the get () method will throw the InvocationTargeTexception. To get the construct () method actually throwing an exception, you can call getTargeTException ().

If the thread of the result is interrupted during the wait result, the GET () method will throw InterruptedException - but this situation is rare for SwingWorker, because the thread of the result is usually the event distribution thread, and in Finished () The result is always ready before calling.

More call tools

SwingWorker's implementation is in the Jozart.swingutils package. In the same package, you can find the InvokeUtils class, which also provides several invokexxxx () methods. The background thread can use these methods to get values ​​and user inputs in the event dispatch thread, and return the results to the background thread.

-------------------------------------------------- -----------------------------

download

The source code of all demonstrations, and compiled class files and resources, including in this zip file:

Threads3 Demos.zip

The threads3_demos.zip file includes the following:

? Jozart /

o DynamICTree / - DynamICTree demo.

o RemoteTable / - RemoteTable bean source.

o RemoteTableDemo / - RemoteTable demos.

o Swingutils / - SwingWorker.

• EDU / - Util.concurrent package (only used by the class).

• Java.Policy - The RMI Security Policy file (Security Policy).

RemoteTable.jar - RemoteTable Bean (for use Ide)

Note: The class from Util.Concurrent is selected from the V1.2.3 version. Only the class used in the demo program is included.

Note: Java 2 is required to run these presentations. (Util.Concurrent package has several collections.)

Run the demo program, first decompress Threads3_Demos.zip to an empty folder, be careful not to change the name of the folder inside. Then change to the folder you extract the file to the file.

Run DynamicTree

Run DynamAmICTree as an Applet:

> AppletViewer Jozart / DynamicTree / DynamicTree.html

Run DynamAmICTree as an Application:

> Java jozart.dynamictree.dynamictree

Run RemoteTablesDemo

Remote table servers and clients are designed with RMIs to run separately. But RMI may be difficult to set. RMI requires a RMI Registry, an HTTP server and a security policy file. Fortunately, another demo procedure is not so troublesome, I will explain how to run it. RemoteTableDemo packed an editor, a viewer and a server.

Run RemoteTableDemo as an Applet:

> AppletViewer Jozart / RemoteTablesDemo / RemoteTablesDemo.html

Run RemoteTableDemo as an Application:

> Java jozart.remotableDemo.remotableDemo

Run server and client separately

To run the servers and clients, you need to perform the following steps:

1. Determine that RMIREGISTRY is running:

> Start RMIREGISTRY

2. Make sure there is an HTTP server that is running:

> Start httpd

3. Convert to the directory of the demo program.

> Cd threereads3

4. Start the server and client:

> Java -djava.security.policy = java.policy

-Djava.rmi.server.codebase = http:// Host / Threads3 /

Jozart.RemoteTablesDemo.remoteTables

> Java -djava.security.policy = java.policy

-Djava.rmi.server.codebase = http:// Host / Threads3 /

Jozart.remotableDemo.remotableEeditor

> Java -djava.security.policy = java.policy

-Djava.rmi.server.codebase = http:// Host / Threads3 /

Jozart.RemoteTablesDemo.remotableViewer

You need to set your correct host name in the CodeBase settings. You should also check that java.polic does not give too much permissions.

For more information on RMI, see The Java Tutorial (see "Reference" section).

-------------------------------------------------- ----------------------------

in conclusion

This article demonstrates two ways to use threads and model-based components (such as JTABLE and JTREE). And provide a revised SwingWorker tool class.

At the beginning, I explained that the components that build thread safety are difficult. Java provides support for threads and locks in the language level, but this does not make concurrent programming suddenly become easy. Swing's single-threshold rules let programmers are freed from the complexity of thread security, but they have become hindered when they do need threads.

In order to make the future users of my own and my code easier in concurrent programming, I use the toolkit as much as possible to prove effective design patterns and extensive acceptance agreements.

At the end of the article, I want to give any readers who are interested in extending SwingWorker or develop their own thread tools: figure out your memory model.

I have to say anything about the access control of shared resources. Java's Synchronized statement ensures the security of the value between the thread. This important detail is often ignored by the programmers. More information about Java memory models can refer to Doug LEA's online supplement to "Concurrent Programming In Java". The links to this reference and other references are listed in the next section.

-------------------------------------------------- ----------------------------- Reference

1. Threads and swing - Hans Muller and kathy Walrath.

2. USING A SWING WORKER THREAD - HANS Muller and Kathy Walrath.

3. Understanding The Treemodel - Eric Armstrong, Tom Santos, Steve Wilson.

4. The Jtable Class Is DB-Aware - Philip Milne and Mark Andrews.

5. The Java Tutorial on RMI - Ann Wollrath and Jim Waldo.

6. Concurrent Programming in Java - Doug LEA.

7. Util.Concurrent Package - Doug Lea.

-------------------------------------------------- -----------------------------

About author

Joseph Bowbeer is a Java consultant living in Seattle. He is aimed at concurrent programming of himself to find his direction. He wants to thank Doug Lea, Tom May, David Holmes and Joshua Bloch, thanking them to share their knowledge. Any mistakes and negligence in the article are attributed to himself.

转载请注明原文地址:https://www.9cbs.com/read-16366.html

New Post(0)