/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4530538
* @summary Basic unit test of ThreadInfo.getBlockedCount()
* @author Alexei Guibadoulline and Mandy Chung
*
* @build ThreadExecutionSynchronizer
* @run main ThreadBlockedCount
*/
import java.lang.management.*;
import java.util.concurrent.locks.LockSupport;
public class ThreadBlockedCount {
final static long EXPECTED_BLOCKED_COUNT = 3;
final static int DEPTH = 10;
private static ThreadMXBean mbean
= ManagementFactory.getThreadMXBean();
private static Object a = new Object();
private static Object b = new Object();
private static Object c = new Object();
private static boolean aNotified = false;
private static boolean bNotified = false;
private static boolean cNotified = false;
private static Object blockedObj1 = new Object();
private static Object blockedObj2 = new Object();
private static Object blockedObj3 = new Object();
private static volatile boolean testFailed = false;
private static BlockingThread blocking;
private static BlockedThread blocked;
private static ThreadExecutionSynchronizer thrsync;
public static void main(String args[]) throws Exception {
// Create the BlockingThread before BlockedThread
// to make sure BlockingThread enter the lock before BlockedThread
thrsync = new ThreadExecutionSynchronizer();
blocking = new BlockingThread();
blocking.start();
blocked = new BlockedThread();
blocked.start();
try {
blocking.join();
blocked.join();
} catch (InterruptedException e) {
System.err.println("Unexpected exception.");
e.printStackTrace(System.err);
throw e;
}
if (testFailed) {
throw new RuntimeException("TEST FAILED.");
}
System.out.println("Test passed.");
}
static class BlockedThread extends Thread {
// NOTE: We can't use a.wait() here because wait() call is counted
// as blockedCount. Instead, we use a boolean flag and sleep.
//
public void run() {
// wait Blocking thread
thrsync.signal();
// Enter lock a without blocking
synchronized (a) {
// wait until BlockingThread holds blockedObj1
while (!aNotified) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
System.err.println("Unexpected exception.");
e.printStackTrace(System.err);
testFailed = true;
}
}
// signal BlockingThread.
thrsync.signal();
// Block to enter blockedObj1
// blockedObj1 should be owned by BlockingThread
synchronized (blockedObj1) {
System.out.println("BlockedThread entered lock blockedObj1.");
}
}
// signal BlockingThread.
thrsync.signal();
// Enter lock a without blocking
synchronized (b) {
// wait until BlockingThread holds blockedObj2
while (!bNotified) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
System.err.println("Unexpected exception.");
e.printStackTrace(System.err);
testFailed = true;
}
}
// signal BlockingThread.
thrsync.signal();
// Block to enter blockedObj2
// blockedObj2 should be owned by BlockingThread
synchronized (blockedObj2) {
System.out.println("BlockedThread entered lock blockedObj2.");
}
}
// signal BlockingThread.
thrsync.signal();
// Enter lock a without blocking
synchronized (c) {
// wait until BlockingThread holds blockedObj3
while (!cNotified) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
System.err.println("Unexpected exception.");
e.printStackTrace(System.err);
testFailed = true;
}
}
// signal BlockingThread.
thrsync.signal();
// Block to enter blockedObj3
// blockedObj3 should be owned by BlockingThread
synchronized (blockedObj3) {
System.out.println("BlockedThread entered lock blockedObj3.");
}
}
// Check the mbean now
ThreadInfo ti = mbean.getThreadInfo(Thread.currentThread().
getId());
long count = ti.getBlockedCount();
if (count != EXPECTED_BLOCKED_COUNT) {
System.err.println("TEST FAILED: Blocked thread has " + count +
" blocked counts. Expected " +
EXPECTED_BLOCKED_COUNT);
testFailed = true;
}
} // run()
} // BlockingThread
static class BlockingThread extends Thread {
private void waitForSignalToRelease() {
// wait for BlockedThread.
thrsync.waitForSignal();
boolean threadBlocked = false;
while (!threadBlocked) {
// give a chance for BlockedThread to really block
try {
Thread.sleep(50);
} catch (InterruptedException e) {
System.err.println("Unexpected exception.");
e.printStackTrace(System.err);
testFailed = true;
}
ThreadInfo info = mbean.getThreadInfo(blocked.getId());
threadBlocked = (info.getThreadState() == Thread.State.BLOCKED);
}
}
public void run() {
// wait for BlockedThread.
thrsync.waitForSignal();
synchronized (blockedObj1) {
System.out.println("BlockingThread attempts to notify a");
aNotified = true;
waitForSignalToRelease();
}
// wait for BlockedThread.
thrsync.waitForSignal();
// block until BlockedThread is ready
synchronized (blockedObj2) {
System.out.println("BlockingThread attempts to notify b");
bNotified = true;
waitForSignalToRelease();
}
// wait for BlockedThread.
thrsync.waitForSignal();
// block until BlockedThread is ready
synchronized (blockedObj3) {
System.out.println("BlockingThread attempts to notify c");
cNotified = true;
waitForSignalToRelease();
}
} // run()
} // BlockedThread
}