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

(thread) There is no documented thread safe way to destroy a ThreadGroup

    XMLWordPrintable

Details

    • Bug
    • Resolution: Won't Fix
    • P4
    • None
    • 7
    • core-libs

    Description

      FULL PRODUCT VERSION :
      java version " 1.7.0_13 "
      Java(TM) SE Runtime Environment (build 1.7.0_13-b20)
      Java HotSpot(TM) Client VM (build 23.7-b01, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      OS version is irrelevant, but here it is: Microsoft Windows [Version 6.1.7601]

      A DESCRIPTION OF THE PROBLEM :
      If you want to destroy a ThreadGroup in a concurrency safe manner you have to do this:

      final ThreadGroup tg = ...;
      synchronized (tg) {
        if ( !tg.isDestroyed() && tg.activeCount() == 0 ) {
          tg.destroy();
        }
      }

      However, this knowledge can only be obtained from looking at the implementation's source code. The JavaDocs do not mention it. See
      http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadGroup.html

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Look at the JavaDoc at http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadGroup.html

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The documentation mentions in the header section (and possibly in method documentations as well) that a user of a ThreadGroup must hold the monitor of the instance to safely check whether the instance can be destroyed.
      ACTUAL -
      No hints in the documentation to the fact that thread safe destruction can be achieved by holding the monitor of the instance.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      If the race condition shows up it looks like this:
      Exception in thread " main " java.lang.IllegalThreadStateException
      at java.lang.ThreadGroup.destroy(ThreadGroup.java:775)
      at ...


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package threads;

      public final class SafeThreadGroupDestroy {

          private static final class DummyRunner implements Runnable {
      @Override
      public void run() {
          try {
      Thread.sleep(200);
          } catch (InterruptedException e) {
      // NOP
          }
      }
          }

          public static void main(String[] args) throws InterruptedException {
      testSuccess();
      testFail();
          }

          private static void startCreator(final ThreadGroup tg,
          final DummyRunner runner) {
      new Thread(new Runnable() {

          @Override
          public void run() {
      try {
          for (;;) {
      new Thread(tg, runner).start();
          }
      } catch (Throwable e) {
          System.out.println( " stop creating " );
      }
          }
      }).start();

      try {
          Thread.sleep(200);
      } catch (InterruptedException e) {
          // NOP
      }
          }

          private static void testSuccess() {
      final ThreadGroup tg = new ThreadGroup( " test " );
      final DummyRunner runner = new DummyRunner();
      new Thread(tg, runner).start(); // ensure there is one thread
      System.out.println( " active: " + tg.activeCount());

      boolean destroyed = false;
      do {
          synchronized (tg) {
      if (!tg.isDestroyed() && tg.activeCount() == 0) {
          // simulate race condition: concurrent creation of another
          // thread at this point in time.
          startCreator(tg, runner);
          tg.destroy();
          destroyed = true;
      }
          }
      } while (!destroyed);
      System.out.println( " destroyed " );
          }

          private static void testFail() {
      final ThreadGroup tg = new ThreadGroup( " test " );
      final DummyRunner runner = new DummyRunner();
      new Thread(tg, runner).start(); // ensure there is one thread
      System.out.println( " active: " + tg.activeCount());

      boolean destroyed = false;
      do {
          if (!tg.isDestroyed() && tg.activeCount() == 0) {
      // simulate race condition: concurrent creation of another
      // thread at this point in time.
      startCreator(tg, runner);
      tg.destroy();
      destroyed = true;
          }
      } while (!destroyed);
      System.out.println( " destroyed " );
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Inspect sources of ThreadGroup to find out that holding the mutex of this allows for thread safe destruction.

      Attachments

        Activity

          People

            alanb Alan Bateman
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: