-
Bug
-
Resolution: Unresolved
-
P4
-
6u10
-
generic
-
generic
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
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