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

Applet deadlocks at startup - AppletPanel violates Swing single-thread rule

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P3
    • Resolution: Cannot Reproduce
    • Affects Version/s: 1.4.2
    • Fix Version/s: None
    • Component/s: client-libs
    • Labels:
    • Subcomponent:
    • CPU:
      x86
    • OS:
      windows_2000

      Description

      FULL PRODUCT VERSION :
      java version "1.4.2_06"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_06-b03)
      Java HotSpot(TM) Client VM (build 1.4.2_06-b03, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Win2K + SP4

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      IE 6.0 + Java 1.4.2_06 plugin

      A DESCRIPTION OF THE PROBLEM :
      Applet's start() method, following the "new" Swing threading rules
      espoused in Sun Bug # 5042754 constructs a simple GUI
      entirely on the event dispatch thread. Yet, when the applet
      attempts to insert text into a JTextArea from the event dispatch
      thread, it deadlocks. The reason for the deadlock is that the
      applet launching code in the sun.applet.AppletPanel,run() method
      itself violates the "new" rule. While running NOT on the EDT,
      the AppletPanel.run() does:

      //...
      case APPLET_START:
      {
      if (status != APPLET_INIT) {
                              showAppletStatus("notinited");
      break;
      }
      applet.resize(currentAppletSize);
      applet.start();
      validate();

      // Show the applet in event dispatch thread
      // to avoid deadlock.
      try
      {
      final Applet a = applet;

      SwingUtilities.invokeAndWait(new Runnable()
      //...

      Since the thread running the validate() above is NOT the EDT,
      the above code is violating the "new" rule. In fact, the above code
      has been observed to be the cause of a deadlock in a real-world
      applet that follows the "new" rule.

      The example applet (in Test Case section) has some interlocking
      wait/notify constructs added to ensure reproducibility of this bug
      every time run. Without the wait/notify code in place, this bug has
      been observed, but, being an MT bug, is difficult to reproduce.

      Here are the stack traces from the two deadlocked threads:

      Thread AWT-EventQueue-2 is holding the writeLock on the JTextArea's
      document and attempting to acquire the AWT tree lock.

      Thread [AWT-EventQueue-2] (Suspended)
      TestApplet$3(java.awt.Component).invalidate() line: 2117
      TestApplet$3(java.awt.Container).invalidate() line: 1038
      TestApplet$3(javax.swing.JComponent).revalidate() line: 4389
      javax.swing.plaf.basic.BasicTextUI$RootView.preferenceChanged(javax.swing.text.View, boolean, boolean) line: 1291
      javax.swing.text.PlainView(javax.swing.text.View).preferenceChanged(javax.swing.text.View, boolean, boolean) line: 302
      javax.swing.text.PlainView.updateDamage(javax.swing.event.DocumentEvent, java.awt.Shape, javax.swing.text.ViewFactory) line: 524
      javax.swing.text.PlainView.insertUpdate(javax.swing.event.DocumentEvent, java.awt.Shape, javax.swing.text.ViewFactory) line: 421
      javax.swing.plaf.basic.BasicTextUI$RootView.insertUpdate(javax.swing.event.DocumentEvent, java.awt.Shape, javax.swing.text.ViewFactory) line: 1487
      javax.swing.plaf.basic.BasicTextUI$UpdateHandler.insertUpdate(javax.swing.event.DocumentEvent) line: 1726
      TestApplet$2(javax.swing.text.AbstractDocument).fireInsertUpdate(javax.swing.event.DocumentEvent) line: 184
      TestApplet$2.fireInsertUpdate(javax.swing.event.DocumentEvent) line: 100
      TestApplet$2(javax.swing.text.AbstractDocument).handleInsertString(int, java.lang.String, javax.swing.text.AttributeSet) line: 749
      TestApplet$2(javax.swing.text.AbstractDocument).insertString(int, java.lang.String, javax.swing.text.AttributeSet) line: 706
      TestApplet$2(javax.swing.text.PlainDocument).insertString(int, java.lang.String, javax.swing.text.AttributeSet) line: 114
      TestApplet$3(javax.swing.JTextArea).append(java.lang.String) line: 465
      TestApplet$1.run() line: 60
      java.awt.event.InvocationEvent.dispatch() line: 178
      java.awt.EventQueue.dispatchEvent(java.awt.AWTEvent) line: 454
      java.awt.EventDispatchThread.pumpOneEventForHierarchy(int, java.awt.Component) line: 201
      java.awt.EventDispatchThread.pumpEventsForHierarchy(int, java.awt.Conditional, java.awt.Component) line: 151
      java.awt.EventDispatchThread.pumpEvents(int, java.awt.Conditional) line: 145
      java.awt.EventDispatchThread.pumpEvents(java.awt.Conditional) line: 137
      java.awt.EventDispatchThread.run() line: 100

      Thread applet-TestApplet.class is holding AWT tree lock
      and attempting to acquire the readLock on the JTextArea's
      document.

      Thread [thread applet-TestApplet.class] (Suspended)
      java.lang.Object.wait(long) line: not available [native method]
      TestApplet$2(java.lang.Object).wait() line: 429
      TestApplet$2(javax.swing.text.AbstractDocument).readLock() line: 1385
      javax.swing.plaf.basic.BasicTextAreaUI(javax.swing.plaf.basic.BasicTextUI).getPreferredSize(javax.swing.JComponent) line: 797
      TestApplet$3(javax.swing.JComponent).getPreferredSize() line: 1275
      TestApplet$3(javax.swing.JTextArea).getPreferredSize() line: 612
      TestApplet$3.getPreferredSize() line: 134
      javax.swing.ScrollPaneLayout$UIResource(javax.swing.ScrollPaneLayout).layoutContainer(java.awt.Container) line: 769
      javax.swing.JScrollPane(java.awt.Container).layout() line: 1020
      javax.swing.JScrollPane(java.awt.Container).doLayout() line: 1010
      javax.swing.JScrollPane(java.awt.Container).validateTree() line: 1092
      javax.swing.JPanel(java.awt.Container).validateTree() line: 1099
      javax.swing.JLayeredPane(java.awt.Container).validateTree() line: 1099
      javax.swing.JRootPane(java.awt.Container).validateTree() line: 1099
      TestApplet(java.awt.Container).validateTree() line: 1099
      sun.plugin.AppletViewer(java.awt.Container).validateTree() line: 1099
      sun.plugin.AppletViewer(java.awt.Container).validate() line: 1067
      sun.plugin.AppletViewer(sun.applet.AppletPanel).run() line: 378
      java.lang.Thread.run() line: 534

      Threads AWT-EventQueue-2 and applet-TestApplet.class are deadlocked.

      There is nothing the developer can do to resolve this issue. It's up to Sun to correct
      the violation of the Swing thread rule (per Sun Bug # 5042754) in AppletPanel.run().


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1) run the TestApplet
      2) attach debugger and observe deadlocked threads

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The applet should not deadlock. Perhaps it should wait for an event that
      will not occur (on one of the TestApplet's "lock" objects), but it should
      not deadlock with one thread holding the document lock and waiting
      for the AWT tree lock and the other thread holding the AWT tree lock and
      waiting for the document lock.
      ACTUAL -
      Threads AWT-EventQueue-2 and applet-TestApplet.class are deadlocked.


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      Here is the example applet that will deadlock every time run:


      import java.awt.BorderLayout;
      import java.awt.Color;
      import java.awt.Dimension;
      import java.awt.HeadlessException;
      import java.awt.Insets;

      import javax.swing.BorderFactory;
      import javax.swing.JApplet;
      import javax.swing.JPanel;
      import javax.swing.JScrollPane;
      import javax.swing.JTextArea;
      import javax.swing.SwingUtilities;
      import javax.swing.event.DocumentEvent;
      import javax.swing.text.PlainDocument;

      /*
       * Demonstrate AppletPanel bug.
       * see: related bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5042754
       * @author Terry Rosenbaum
       * @version 1.0 Nov 14, 2004
       */
      public class TestApplet extends JApplet
      {
          JTextArea itsTextArea;
          Thread itsLauncherThread;
          final Object itsWriteLockHeldLock = new Object();
          boolean itsWriteLockHeld;
          final Object itsTreeLockHeldLock = new Object();
          boolean itsTreeLockHeld;
          boolean itsGUIConstructionCompleted;
          
          /**
           * @throws java.awt.HeadlessException
           */
          public TestApplet() throws HeadlessException
          {
              super();
          }
          
          public void init()
          {
              
          }
          
      public void start()
      {
      SwingUtilities.invokeLater(
      new Runnable()
      {
      public void run()
      {
      doStart();
      }
      }
      );
      }

          public void doStart()
          {
              itsLauncherThread = Thread.currentThread();
              constructGUI();
              itsGUIConstructionCompleted = true;
              final JTextArea aTextArea = itsTextArea;
              
              // enqueue the text area update on the Swing event queue
              SwingUtilities.invokeLater
              (
                  new Runnable()
                  {
                      public void run()
                      {
                          aTextArea.append("This is some text\n");
                      }
                  }
              );
          }

          void constructGUI()
          {
              PlainDocument aDocument = new PlainDocument()
              {
                  protected void fireInsertUpdate(DocumentEvent e)
                  {
                      if(Thread.currentThread() != itsLauncherThread)
                      {
                          // looking at the code, we know write lock is held now
                          // notify other thread that we now hold the write lock
                          synchronized(itsWriteLockHeldLock)
                          {
                              itsWriteLockHeld = true;
                              itsWriteLockHeldLock.notify();
                          }
                          
                          // wait until other thread notifies us that it holds the AWT tree lock
                          synchronized(itsTreeLockHeldLock)
                          {
                              while(!itsTreeLockHeld)
                              {
                                  try
                                  {
                                      itsTreeLockHeldLock.wait();
                                  }
                                  catch(InterruptedException anException)
                                  {
                                      anException.printStackTrace();
                                  }
                              }
                          }
                          // enter the deadlock
                      }
                      // continue with original Sun implementation
                      super.fireInsertUpdate(e);
                  }
              };
              itsTextArea = new JTextArea(aDocument, null, 6, 40)
              {
                  public Dimension getPreferredSize()
                  {
                      if(itsGUIConstructionCompleted && Thread.currentThread() == itsLauncherThread)
                      {
                          // wait for the thread running the AWT event queue
                          // to notify us that it holds the write lock
                          synchronized(itsWriteLockHeldLock)
                          {
                              while(!itsWriteLockHeld)
                              {
                                  try
                                  {
                                      itsWriteLockHeldLock.wait();
                                  }
                                  catch(InterruptedException anException)
                                  {
                                      anException.printStackTrace();
                                  }
                              }
                          }
                          
                          // notify the other thread that we hold the AWT tree lock
                          synchronized(itsTreeLockHeldLock)
                          {
                              itsTreeLockHeld = true;
                              itsTreeLockHeldLock.notify();
                          }
                          // enter the deadlock
                      }
                      return super.getPreferredSize();
                  };
              };
              itsTextArea.setMargin(new Insets(5,5,5,5));
              itsTextArea.setEditable(false);

              JPanel aPanel = new JPanel();
              aPanel.setBackground(new Color(0xE1E5E8));
              aPanel.setForeground(new Color(0xE1E5E8));
              aPanel.setLayout(new BorderLayout());
              
              JScrollPane aScrollPane = new JScrollPane(itsTextArea);
              aScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
              aScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
              aPanel.add(aScrollPane, BorderLayout.CENTER);
              aPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
              setContentPane(aPanel);
          }
      }

      ---------- END SOURCE ----------
      ###@###.### 2004-11-15 23:41:59 GMT

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                dcherepanov Dmitry Cherepanov
                Reporter:
                gmanwanisunw Girish Manwani (Inactive)
              • Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Imported:
                  Indexed: