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

Cant detect deadlock when thread reenters synchronization block in Object.wait()

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P4
    • tbd
    • 6u10
    • core-svc

    Description

      FULL PRODUCT VERSION :
      java version "1.6.0_10"
      Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
      Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)


      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [Version 5.2.3790]


      A DESCRIPTION OF THE PROBLEM :
      Methods ThreadMXBean.findMonitorDeadlockedThreads() and ThreadMXBean.findDeadlockedThreads() are unable to detect deadlock when one thread reenters synchronization block after Object.wait() call in case of pure monitors or after java.util.concurrent.locks.Condition.await() call in case of ReentrantLock or ReentrantReadWriteLock.

      see test case below

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      unable to detect deadlock
      ACTUAL -
      such deadlock should be detected

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.lang.management.ManagementFactory;
      import java.lang.management.ThreadInfo;
      import java.lang.management.ThreadMXBean;
      import java.util.concurrent.locks.Condition;
      import java.util.concurrent.locks.Lock;
      import java.util.concurrent.locks.ReentrantLock;
      import java.util.concurrent.locks.ReentrantReadWriteLock;

      import org.junit.Assert;
      import org.junit.Before;
      import org.junit.Test;

      public class FindDeadlockTest {
      private ThreadMXBean threadMxBean;

      @Before
      public void setUp() {
      threadMxBean = ManagementFactory.getThreadMXBean();
      }

      @Test
      public void testMonitorReacquiranceFromWait() {
      final Object LOCK0 = new Object();
      final Object LOCK1 = new Object();
      String threadNamePrefix = "MonitorReacquiranceFromWait";
      start(threadNamePrefix + "-0", new Runnable() {
      public void run() {
      try {
      synchronized (LOCK0) {
      synchronized (LOCK1) {
      LOCK0.wait();
      }
      }
      } catch (InterruptedException exc) {
      // ignore
      }
      }
      });
      start(threadNamePrefix + "-1", new Runnable() {
      public void run() {
      sleep(1000);
      synchronized (LOCK0) {
      LOCK0.notify();
      synchronized (LOCK1) {
      // no nothing
      }
      }
      }
      });
      sleep(2000);
      check(threadNamePrefix, threadMxBean.findMonitorDeadlockedThreads(), 2);
      check(threadNamePrefix, threadMxBean.findDeadlockedThreads(), 2);
      }

      @Test
      public void testReentrantLockReacquiranceFromAwait() {
      final Lock LOCK0 = new ReentrantLock();
      final Lock LOCK1 = new ReentrantLock();
      // final Lock LOCK0 = new ReentrantReadWriteLock().writeLock();
      // final Lock LOCK1 = new ReentrantReadWriteLock().writeLock();
      final Condition COND0 = LOCK0.newCondition();
      String threadNamePrefix = "ReentrantLockReacquiranceFromAwait";
      start(threadNamePrefix + "-0", new Runnable() {
      public void run() {
      try {
      LOCK0.lock();
      try {
      LOCK1.lock();
      try {
      COND0.await();
      } finally {
      LOCK1.unlock();
      }
      } finally {
      LOCK0.unlock();
      }
      } catch (InterruptedException exc) {
      // ignore
      }
      }
      });
      start(threadNamePrefix + "-1", new Runnable() {
      public void run() {
      sleep(1000);
      LOCK0.lock();
      try {
      COND0.signal();
      LOCK1.lock();
      try {
      // no nothing
      } finally {
      LOCK1.unlock();
      }
      } finally {
      LOCK0.unlock();
      }
      }
      });
      sleep(2000);
      check(threadNamePrefix, threadMxBean.findDeadlockedThreads(), 2);
      }

      static void sleep(long millis) {
      try {
      Thread.sleep(millis);
      } catch (InterruptedException exc) {
      // ignore
      }
      }

      static void start(String name, Runnable r) {
      Thread thread = new Thread(r, name);
      thread.setDaemon(true);
      thread.start();
      }

      void check(String threadNamePrefix, long[] ids, int expectedNumberOfDeadlockedThreads) {
      int actualNumberOfDeadlockedThreads = 0;
      if (ids != null) {
      for (ThreadInfo info : threadMxBean.getThreadInfo(ids)) {
      if (info.getThreadName().startsWith(threadNamePrefix)) {
      ++actualNumberOfDeadlockedThreads;
      }
      }
      }
      Assert.assertEquals("number of deadlocked threads", expectedNumberOfDeadlockedThreads, actualNumberOfDeadlockedThreads);
      }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      use own code for deadlock detection

      Attachments

        Activity

          People

            Unassigned Unassigned
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Imported:
              Indexed: