Desktop Java

April 2005

Desktop Java

The following is a sample chapter from SourceBeat’s Destop Java Live by Scott

Delap. You can access more information about this book and our other titles at

www.sourcebeat.com.

SourceBeat’s publishing model is quite different than traditional publishers in that our

books are updated monthly and accessed electronically via secure PDF files. Readers

subscribe annually to each title for $29.95 and receive updates throughout the

subscription life.

Thank you for your interest in this title.

CHAPTER 5

Swing Threading

Desktop applications are often multi-threaded in nature. While adding benefits to responsiveness and

performance, multi-threading adds coding complexity. You can write Swing applications without using

multiple threads. However, once you cross the line into having a multi-threaded application, you

should abide by Swing’s threading rules. Otherwise, your application may behave in an unpredictable

manner. In this chapter, you’ll explore how Swing uses threads. You’ll then view a number of

threading-related resources in the Swing API. You’ll also be introduced to three structured Swing

threading solutions: SwingWorker, Foxtrot, and Spin. Finally, you’ll learn how to detect incorrect

thread usage in Swing with a custom repaint manager.

Swing, AWT, and the EDT

PAGE 142 Desktop Java Live

Swing, AWT, and the EDT

Swing is built on top of Java’s Abstract Windowing Toolkit (AWT). AWT uses native code to

access the underlying operating system’s components. Each component in AWT, such as a

button, has a corresponding native peer that requests use, for example when it needs to draw

that it has been pressed. Swing, on the other hand, does not use native peer components

except for a few rare exceptions. Instead, it paints components completely in Java on top of a

canvas provided by AWT. An example of this is shown in Chapter 4; the AnimatedGradientButtonUI

paints a special effect when a button has focus. Because Swing exists on top of AWT, it

takes advantage of the AWT event-dispatching framework.

When you start a Swing application, three threads are executed: the main application thread, a

toolkit thread and the event dispatch thread. The main application thread calls the main() method

to start the application. The toolkit thread dispatches events from the native operating

system, which make their way to the AWT event dispatch thread, called the EDT. The EDT

handles two primary functions. First, it dispatches events, such as mouse clicks, to the appropriate

Swing component. Second, it executes paint operations of Swing components.

Note: When a thread other than the EDT executes code, it is often described as “off the EDT.”

Correspondingly, code executed by the EDT when it processes events is often described as “on the

EDT.” Finally, using threads other than the EDT in your application causes your application to be

“multi-threaded.”

When a mouse click occurs, for instance on a JButton, an event is generated. AWT dispatches

this event to the Jbutton, which fires a mouse event to its listeners, one of which is its UI delegate.

The delegate then paints the JButton’s visible state to appear pressed. From the time the

event is dispatched until the paint operation is performed, the code is executed on the EDT.

You may be wondering what this has to do with threading, because AWT seems to have the

situation handled. AWT, for the most part, has things under control; however, if you’ve

written Swing code, you’ve probably encountered times when your application froze. Figure

5.1 and the subsequent code show a situation that will cause a freeze.

Swing, AWT, and the EDT

PAGE 143 Chapter 5: Swing Threading

Figure 5.1: A JButton Experiencing a Freeze after Mouse Down

public JPanel createPanel() {

JPanel panel = new JPanel();

panel.setLayout(new FormLayout("p:g", "p, p, f:d:g"));

CellConstraints cc = new CellConstraints();

JButton button = new JButton(new FreezeAction());

panel.add(button, cc.xy(1, 1));

JButton button1 = new JButton("Other Button");

panel.add(button1, cc.xy(1, 2));

Vector values = new Vector();

for (int i = 0; i < 100; i++) {

values.add("Value" + i);

}

JList list = new JList(values);

panel.add(new JScrollPane(list), cc.xy(1, 3));

return panel;

}

private class FreezeAction extends AbstractAction {

Swing, AWT, and the EDT

PAGE 144 Desktop Java Live

At first glance, you see two buttons and a list contained in a panel. However, notice the

Thread.sleep() method calls in the appropriately named FreezeAction. Clicking the Freeze EDT

button will result in the button staying “stuck” in a pressed state for five seconds. The button

doesn’t return to its normal state because the sleep() method is applied to the EDT, and stops

any further processing of input or paint events.

public FreezeAction() {

super("Freeze EDT");

}

public void actionPerformed(ActionEvent e) {

try {

Thread.sleep(5000);

} catch (InterruptedException e1) {

}

}

}

The Event Queue and Processing

PAGE 145 Chapter 5: Swing Threading

The Event Queue and Processing

Events, such as moving the mouse, are created and placed in a queue called the EventQueue.

The EDT then processes these events sequentially. Figure 5.2 and the subsequent code

expand on the previous example, illustrating some of the input events processed by the EDT.

Figure 5.2: Echoing Events as They Are Processed by the EDT

In this example, an AWTEventListener is added to the default toolkit.

public JPanel createPanel() {

JPanel panel = new JPanel();

panel.setLayout(new FormLayout("p:g", "p, p, p, f:d:g"));

CellConstraints cc = new CellConstraints();

...

JTextArea textArea = new JTextArea();

textArea.setAutoscrolls(false);

JScrollPane textScrollPane = new JScrollPane(textArea);

textScrollPane.setHorizontalScrollBarPolicy(

The Event Queue and Processing

PAGE 146 Desktop Java Live

JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

textScrollPane.setVerticalScrollBarPolicy(

JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

panel.add(textScrollPane, cc.xy(1, 4));

Toolkit.getDefaultToolkit().addAWTEventListener(

new EchoingAWTListener(textArea),

AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);

return panel;

}

private class ToggleEchoAction extends AbstractAction {

public ToggleEchoAction() {

super("Echo AWT Events");

}

public void actionPerformed(ActionEvent e) {

EDTListenerExample.this.echo = !EDTListenerExample.this.echo;

if (EDTListenerExample.this.echo) {

putValue(Action.NAME, "Disable Echo");

} else {

putValue(Action.NAME, "Echo AWT Events");

}

}

}

private class EchoingAWTListener implements AWTEventListener {

private JTextArea textArea;

private int count;

public EchoingAWTListener(JTextArea textArea) {

this.textArea = textArea;

The Event Queue and Processing

PAGE 147 Chapter 5: Swing Threading

}

public void eventDispatched(AWTEvent event) {

if (EDTListenerExample.this.echo) {

String eventName = getEventType(event.getID());

if (eventName != null) {

this.count++;

textArea.append("/n" +

this.count + " - " + eventName);

}

}

}

private String getEventType(int id) {

switch (id) {

case KeyEvent.KEY_PRESSED:

return "KEY_PRESSED";

case KeyEvent.KEY_RELEASED:

return "KEY_RELEASED";

case MouseEvent.MOUSE_PRESSED:

return "MOUSE_PRESSED";

case MouseEvent.MOUSE_RELEASED:

return "MOUSE_RELEASED";

case MouseEvent.MOUSE_MOVED:

return "MOUSE_MOVED";

case MouseEvent.MOUSE_DRAGGED:

return "MOUSE_DRAGGED";

case MouseEvent.MOUSE_ENTERED:

return "MOUSE_ENTERED";

case MouseEvent.MOUSE_EXITED:

return "MOUSE_EXITED";

case MouseEvent.MOUSE_WHEEL:

return "MOUSE_WHEEL";

default:

The Event Queue and Processing

PAGE 148 Desktop Java Live

In this example, an AWTEventListener is added to the default toolkit.

Note: An AWTEventListener can slow your application down because it is executed on every AWT

event.

This listener is triggered every time an event is processed. Clicking the Echo AWT Events

button lists (or echoes) all mouse and keyboard events in the text area. For instance, if you run

this example and click the Freeze EDT button, ‘MOUSE_PRESSED’ will appear in the text

area, which corresponds to clicking the mouse. At this point, the Thread.sleep() method begins

to run, so the EDT can no longer process events. As a result, events stay queued; no events

are processed until the Thread.sleep() method is finished. Upon the method’s completion, the

queued events are processed sequentially (including the MOUSE_RELEASED event after

clicking the button).

Freeze issues in most Swing applications occur when long running (or heavyweight) operations

on the EDT are executed, which blocks the processing of other events. Often, it is not

obvious that such operations are running on the EDT. By default, all Swing operations

including, actionPerformed() methods in actions and listeners are executed on the EDT. You will

see a number of ways to free up the EDT later in this chapter. First, you need to be aware of

the Single Threading Rule of Swing.

The Single Threading Rule

The Swing Single Threading Rule states the following:

To avoid the possibility of deadlock, you must take extreme care that Swing components

and models are created, modified, and queried only from the event-dispatching

thread.1

return null;

}

}

}

1. Sun Microsystems, Inc. “How to Use Threads.” Sun Microsystems, Inc. 1995-2005. http://java.sun.com/

docs/books/tutorial/uiswing/misc/threads.html

The Event Queue and Processing

PAGE 149 Chapter 5: Swing Threading

Swing was designed with the assumption that all access to Swing components is executed on

the EDT. Consequently, Swing components are not designed to be thread-safe. Therefore,

any time you access Swing components from threads other than the EDT, common threading

problems may exist, such as race conditions and deadlocks. The Single Threading Rule has

evolved slightly over the years. It was once thought that components could be accessed from

the EDT as long as you didn’t modify them after they had been realized, that is, painted or

ready to be painted. Using this definition, the following code was considered safe:

However, Sun’s engineers found that in a few of the Swing tutorial examples, even unrealized

components being accessed from the EDT caused problems. For instance, one of the official

Swing tutorial examples intermittently had deadlock problems. Therefore, component

creation should only occur on the EDT just like other Swing component manipulation. You

will learn how to put code, such as the frame creation example, on the EDT from another

thread later in this chapter.

Why Single Threading?

The single-threaded architecture of Swing is useful for a number of reasons.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值