Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4077061

AWT components do not use AWTEventMulticaster in a threadsafe way

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Cannot Reproduce
    • Icon: P4 P4
    • None
    • 1.1.3, 1.1.8_003
    • client-libs
    • 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 - ###@###.###
      ======================================================================

            rraysunw Richard Ray (Inactive)
            johsunw Joon Oh (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: