-
Bug
-
Resolution: Cannot Reproduce
-
P4
-
None
-
1.1.3, 1.1.8_003
-
x86
-
windows_nt
Name: joT67522 Date: 09/05/97
The code sample in the documentation for java.awt.AWTEventMulticaster
is not threadsafe. Almost all of the AWT components
use AWTEventMulticaster in the same manner. If a thread removes the last listener
as events are being fired, a NullPointerException can be thrown.
The documented usage sample is this:
public myComponent extends Component {
ActionListener actionListener = null;
public void addActionListener(ActionListener l) {
actionListener = AWTEventMulticaster.add(actionListener, l);
}
public void removeActionListener(ActionListener l) {
actionListener = AWTEventMulticaster.remove(actionListener, l);
}
public void processEvent(AWTEvent e) {
// when event occurs which causes "action" semantic
if (actionListener != null) {
actionListener.actionPerformed(new ActionEvent());
}
}
}
In processEvent() another thread could remove the last listener
after the check for null, resulting in actionPerformed() being called
on a null pointer. Most AWT components I checked have this same problem
(e.g. Component, Button, Checkbox, Choice, List etc.)
Here is a fixed processEvent() sample implementation:
public void processEvent(AWTEvent e) {
ActionListener temp = actionListener;
// when event occurs which causes "action" semantic
if (temp != null) {
temp.actionPerformed(new ActionEvent());
}
}
Here is some sample code which demonstrates the problem
using a Frame and FocusEvents. One thread continually
adds and removes a single focus listener from the frame. The other thread
continually dispatches focus events to the frame.
After running this sample for a few seconds a NullPointerException
is thrown:
java.lang.NullPointerException:
at java.awt.Component.processFocusEvent(Component.java:1843)
at java.awt.Component.processEvent(Component.java:1769)
at java.awt.Container.processEvent(Container.java:792)
at java.awt.Window.processEvent(Window.java:273)
at java.awt.Component.dispatchEventImpl(Component.java:1456)
at java.awt.Container.dispatchEventImpl(Container.java:837)
at java.awt.Window.dispatchEventImpl(Window.java:401)
at java.awt.Component.dispatchEvent(Component.java:1393)
at MulticastTester$3.run(MulticastTester.java:43)
at java.lang.Thread.run(Thread.java:474)
I am able to reliably duplicate this using NT 4.0,
other platforms may or may not show the problem with
this sample due to different underlying thread
implementations in the VM.
Here is the sample code:
// Test threadsafe usage of AWTEventMulticaster
import java.awt.*;
import java.awt.event.*;
public class MulticastTester {
public static void main(String args[]) {
final Frame frame = new Frame("Multicast Tester");
frame.setSize(300, 300);
frame.setVisible(true);
Thread thdListener = new Thread(new Runnable() {
public void run() {
boolean bAdd = true;
FocusListener l = new FocusAdapter() {
public void focusGained(FocusEvent e) {
//System.out.println("focusGained");
}
};
while (true) {
if (bAdd) {
//System.out.println("addKeyListener");
frame.addFocusListener(l);
bAdd = false;
}
else {
//System.out.println("removeKeyListener");
frame.removeFocusListener(l);
bAdd = true;
}
Thread.yield();
}
}
});
//thdListener.setPriority(Thread.MAX_PRIORITY);
thdListener.start();
Thread thdEvent = new Thread(new Runnable() {
public void run() {
FocusEvent evt = new FocusEvent(frame, FocusEvent.FOCUS_GAINED);
while (true) {
frame.dispatchEvent(evt);
//Thread.yield();
}
}
});
thdEvent.start();
}
}
company - SoftCom , email - ###@###.###
======================================================================