JDK-6841139 : Cant detect deadlock when thread reenters synchronization block in Object.wait()
  • Type: Bug
  • Component: core-svc
  • Sub-Component: java.lang.management
  • Affected Version: 6u10
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: solaris_8
  • CPU: x86
  • Submitted: 2009-05-14
  • Updated: 2019-05-22
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
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

Comments
SUGGESTED FIX See attached patches copied over from http://bugs.openjdk.java.net/show_bug.cgi?id=100058
23-07-2012