Path: blob/master/test/jdk/java/lang/management/ThreadMXBean/SynchronizationStatistics.java
41152 views
/*1* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 453053826* @summary Basic unit test of the synchronization statistics support:27* @author Mandy Chung28* @author Jaroslav Bachorik29*30* @run main/othervm SynchronizationStatistics31*/3233import java.lang.management.*;34import java.util.concurrent.Phaser;35import java.util.function.Supplier;3637public class SynchronizationStatistics {38private static class LockerThread extends Thread {39public LockerThread(Runnable r) {40super(r, "LockerThread");41}42}4344private static final ThreadMXBean mbean = ManagementFactory.getThreadMXBean();4546private static final boolean blockedTimeCheck =47mbean.isThreadContentionMonitoringSupported();484950public static void main(String args[]) throws Exception {51if (blockedTimeCheck) {52mbean.setThreadContentionMonitoringEnabled(true);53}5455if (!mbean.isThreadContentionMonitoringEnabled()) {56throw new RuntimeException("TEST FAILED: " +57"Thread Contention Monitoring is not enabled");58}5960testBlockingOnSimpleMonitor();61testBlockingOnNestedMonitor();62testWaitingOnSimpleMonitor();63testMultiWaitingOnSimpleMonitor();64testWaitingOnNestedMonitor();6566System.out.println("Test passed.");67}6869private static LockerThread newLockerThread(Runnable r) {70LockerThread t = new LockerThread(r);71t.setDaemon(true);72return t;73}7475private static void waitForThreadState(Thread t, Thread.State state) throws InterruptedException {76while (t.getState() != state) {77Thread.sleep(3);78}79}8081/**82* Tests that blocking on a single monitor properly increases the83* blocked count at least by 1. Also asserts that the correct lock name is provided.84*/85private static void testBlockingOnSimpleMonitor() throws Exception {86System.out.println("testBlockingOnSimpleMonitor");87final Object lock1 = new Object();88System.out.println("Lock1 = " + lock1);8990final Phaser p = new Phaser(2);91LockerThread lt = newLockerThread(new Runnable() {92@Override93public void run() {94p.arriveAndAwaitAdvance(); // phase[1]95synchronized(lock1) {96System.out.println("[LockerThread obtained Lock1]");97p.arriveAndAwaitAdvance(); // phase[2]98}99p.arriveAndAwaitAdvance(); // phase[3]100}101});102103lt.start();104long tid = lt.getId();105ThreadInfo ti = mbean.getThreadInfo(tid);106String lockName = null;107synchronized(lock1) {108p.arriveAndAwaitAdvance(); // phase[1]109waitForThreadState(lt, Thread.State.BLOCKED);110do {111lockName = mbean.getThreadInfo(tid).getLockName();112} while (lockName == null);113}114115p.arriveAndAwaitAdvance(); // phase[2]116testBlocked(ti, () -> mbean.getThreadInfo(tid), lockName, lock1);117p.arriveAndDeregister(); // phase[3]118119lt.join();120121printok();122}123124/**125* Tests that blocking on a nested monitor properly increases the126* blocked count at least by 1 - it is not affected by the nesting depth.127* Also asserts that the correct lock name is provided.128*/129private static void testBlockingOnNestedMonitor() throws Exception {130System.out.println("testBlockingOnNestedMonitor");131final Object lock1 = new Object();132final Object lock2 = new Object();133134System.out.println("Lock1 = " + lock1);135System.out.println("Lock2 = " + lock2);136137final Phaser p = new Phaser(2);138LockerThread lt = newLockerThread(new Runnable() {139@Override140public void run() {141p.arriveAndAwaitAdvance(); // phase[1]142synchronized(lock1) {143System.out.println("[LockerThread obtained Lock1]");144p.arriveAndAwaitAdvance(); // phase[2]145p.arriveAndAwaitAdvance(); // phase[3]146synchronized(lock2) {147System.out.println("[LockerThread obtained Lock2]");148p.arriveAndAwaitAdvance(); // phase[4]149}150p.arriveAndAwaitAdvance(); // phase[5]151}152}153});154155lt.start();156long tid = lt.getId();157ThreadInfo ti = mbean.getThreadInfo(tid);158String lockName = null;159synchronized(lock1) {160p.arriveAndAwaitAdvance(); // phase[1]161waitForThreadState(lt, Thread.State.BLOCKED);162do {163lockName = mbean.getThreadInfo(tid).getLockName();164} while (lockName == null);165}166p.arriveAndAwaitAdvance(); // phase[2]167168ti = testBlocked(ti, () -> mbean.getThreadInfo(tid), lockName, lock1);169170synchronized(lock2) {171p.arriveAndAwaitAdvance(); // phase [3]172waitForThreadState(lt, Thread.State.BLOCKED);173do {174lockName = mbean.getThreadInfo(tid).getLockName();175} while (lockName == null);176}177p.arriveAndAwaitAdvance(); // phase [4]178testBlocked(ti, () -> mbean.getThreadInfo(tid), lockName, lock2);179p.arriveAndDeregister();180181lt.join();182183printok();184}185186/**187* Tests that waiting on a single monitor properly increases the waited188* count by 1 and the waited time by a positive number.189*/190private static void testWaitingOnSimpleMonitor() throws Exception {191System.out.println("testWaitingOnSimpleMonitor");192final Object lock1 = new Object();193final Phaser p = new Phaser(2);194LockerThread lt = newLockerThread(new Runnable() {195@Override196public void run() {197p.arriveAndAwaitAdvance(); // phase[1]198synchronized(lock1) {199System.out.println("[LockerThread obtained Lock1]");200try {201lock1.wait(300);202} catch (InterruptedException ex) {203// ignore204}205p.arriveAndAwaitAdvance(); // phase[2]206}207p.arriveAndAwaitAdvance(); // phase[3]208}209});210211lt.start();212ThreadInfo ti1 = mbean.getThreadInfo(lt.getId());213synchronized(lock1) {214p.arriveAndAwaitAdvance(); // phase[1]215waitForThreadState(lt, Thread.State.BLOCKED);216}217p.arriveAndAwaitAdvance(); // phase[2]218219testWaited(ti1, () -> mbean.getThreadInfo(lt.getId()), 1);220p.arriveAndDeregister(); // phase[3]221222lt.join();223224printok();225}226227/**228* Tests that waiting multiple times on the same monitor subsequently229* increases the waited count by the number of subsequent calls and the230* waited time by a positive number.231*/232private static void testMultiWaitingOnSimpleMonitor() throws Exception {233System.out.println("testWaitingOnMultipleMonitors");234final Object lock1 = new Object();235236final Phaser p = new Phaser(2);237LockerThread lt = newLockerThread(new Runnable() {238@Override239public void run() {240p.arriveAndAwaitAdvance(); // phase[1]241synchronized(lock1) {242System.out.println("[LockerThread obtained Lock1]");243for (int i = 0; i < 3; i++) {244try {245lock1.wait(300);246} catch (InterruptedException ex) {247// ignore248}249p.arriveAndAwaitAdvance(); // phase[2-4]250}251}252p.arriveAndAwaitAdvance(); // phase[5]253}254});255256lt.start();257ThreadInfo ti1 = mbean.getThreadInfo(lt.getId());258synchronized(lock1) {259p.arriveAndAwaitAdvance(); //phase[1]260waitForThreadState(lt, Thread.State.BLOCKED);261}262int phase = p.getPhase();263while ((p.arriveAndAwaitAdvance() - phase) < 3); // phase[2-4]264265testWaited(ti1, () -> mbean.getThreadInfo(lt.getId()), 3);266p.arriveAndDeregister(); // phase[5]267268lt.join();269270printok();271}272273/**274* Tests that waiting on monitors places in nested synchronized blocks275* properly increases the waited count by the number of times the "lock.wait()"276* was invoked and the waited time by a positive number.277*/278private static void testWaitingOnNestedMonitor() throws Exception {279System.out.println("testWaitingOnNestedMonitor");280final Object lock1 = new Object();281final Object lock2 = new Object();282final Object lock3 = new Object();283284final Phaser p = new Phaser(2);285LockerThread lt = newLockerThread(new Runnable() {286@Override287public void run() {288p.arriveAndAwaitAdvance(); // phase[1]289synchronized(lock1) {290System.out.println("[LockerThread obtained Lock1]");291try {292lock1.wait(300);293} catch (InterruptedException ex) {294// ignore295}296297p.arriveAndAwaitAdvance(); // phase[2]298synchronized(lock2) {299System.out.println("[LockerThread obtained Lock2]");300try {301lock2.wait(300);302} catch (InterruptedException ex) {303// ignore304}305306p.arriveAndAwaitAdvance(); // phase[3]307synchronized(lock3) {308System.out.println("[LockerThread obtained Lock3]");309try {310lock3.wait(300);311} catch (InterruptedException ex) {312// ignore313}314p.arriveAndAwaitAdvance(); // phase[4]315}316}317}318p.arriveAndAwaitAdvance(); // phase[5]319}320});321322lt.start();323ThreadInfo ti1 = mbean.getThreadInfo(lt.getId());324synchronized(lock1) {325p.arriveAndAwaitAdvance(); // phase[1]326waitForThreadState(lt, Thread.State.BLOCKED);327}328329synchronized(lock2) {330p.arriveAndAwaitAdvance(); // phase[2]331waitForThreadState(lt, Thread.State.BLOCKED);332}333334synchronized(lock3) {335p.arriveAndAwaitAdvance(); // phase[3]336waitForThreadState(lt, Thread.State.BLOCKED);337}338339p.arriveAndAwaitAdvance(); // phase[4]340testWaited(ti1, () -> mbean.getThreadInfo(lt.getId()), 3);341p.arriveAndDeregister(); // phase[5]342343lt.join();344printok();345}346347private static void printok() {348System.out.println("OK\n");349}350351private static void testWaited(ThreadInfo ti1, Supplier<ThreadInfo> ti2, int waited)352throws InterruptedException {353boolean error;354do {355error = false;356ThreadInfo ti = ti2.get();357long waitCntDiff = ti.getWaitedCount() - ti1.getWaitedCount();358long waitTimeDiff = ti.getWaitedTime() - ti1.getWaitedTime();359if (waitCntDiff < waited) {360System.err.println(361"Unexpected diff in waited count. Expecting at least "362+ waited + " , got " + waitCntDiff363);364error = true;365}366if (waitTimeDiff <= 0) {367System.err.println(368"Unexpected diff in waited time. Expecting increasing " +369"value, got " + waitTimeDiff + "ms"370);371error = true;372}373if (error) {374System.err.println("Retrying in 20ms ...");375Thread.sleep(20);376}377} while (error);378}379380private static ThreadInfo testBlocked(ThreadInfo ti1, Supplier<ThreadInfo> ti2,381String lockName, final Object lock)382throws InterruptedException {383boolean error;384ThreadInfo ti = null;385do {386error = false;387ti = ti2.get();388long blkCntDiff = ti.getBlockedCount() - ti1.getBlockedCount();389long blkTimeDiff = ti.getBlockedTime() - ti1.getBlockedTime();390391System.out.println("testBlocked: [" + blkCntDiff + ", " + blkTimeDiff + ", " + lockName + "]");392393if (blkCntDiff < 1) {394System.err.println(395"Unexpected diff in blocked count. Expecting at least 1, " +396"got " + blkCntDiff397);398error = true;399}400if (blkTimeDiff < 0) {401System.err.println(402"Unexpected diff in blocked time. Expecting a positive " +403"number, got " + blkTimeDiff404);405error = true;406}407if (!lockName.equals(lock.toString())) {408System.err.println(409"Unexpected blocked monitor name. Expecting " +410lock.toString() + ", got " + lockName411);412error = true;413}414if (error) {415System.err.println("Retrying in 20ms ...");416Thread.sleep(20);417}418} while (error);419return ti;420}421}422423424