1 /*
   2  * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug     4530538
  27  * @summary Basic unit test of ThreadInfo.getBlockedCount()
  28  * @author  Alexei Guibadoulline and Mandy Chung
  29  * @author  Jaroslav Bachorik
  30  *
  31  * @run main ThreadBlockedCount
  32  */
  33 
  34 import java.lang.management.*;
  35 import java.util.concurrent.Phaser;
  36 
  37 public class ThreadBlockedCount {
  38         static final long EXPECTED_BLOCKED_COUNT = 3;
  39     static final int  DEPTH = 10;
  40     private static final ThreadMXBean mbean
  41         = ManagementFactory.getThreadMXBean();
  42 
  43     private static final Object a = new Object();
  44     private static final Object b = new Object();
  45     private static final Object c = new Object();
  46 
  47     private static final Object blockedObj1 = new Object();
  48     private static final Object blockedObj2 = new Object();
  49     private static final Object blockedObj3 = new Object();
  50     private static volatile boolean testOk = true;
  51     private static BlockingThread blocking;
  52     private static BlockedThread blocked;
  53 
  54     public static void main(String args[]) throws Exception {
  55         // real run
  56         runTest();
  57         if (!testOk) {
  58             throw new RuntimeException("TEST FAILED.");
  59         }
  60         System.out.println("Test passed.");
  61     }
  62 
  63     private static void runTest() throws Exception {
  64         final Phaser p = new Phaser(2);
  65 
  66         blocking = new BlockingThread(p);
  67         blocking.start();
  68 
  69         blocked = new BlockedThread(p);
  70         blocked.start();
  71 
  72         try {
  73             blocking.join();
  74 
  75             testOk = checkBlocked();
  76             p.arriveAndAwaitAdvance(); // #5
  77 
  78         } catch (InterruptedException e) {
  79             System.err.println("Unexpected exception.");
  80             e.printStackTrace(System.err);
  81             throw e;
  82         }
  83     }
  84 
  85 
  86     static class BlockedThread extends Thread {
  87         private final Phaser p;
  88 
  89         BlockedThread(Phaser p) {
  90             super("BlockedThread");
  91             this.p = p;
  92         }
  93 
  94         public void run() {
  95             int accumulator = 0;
  96             p.arriveAndAwaitAdvance(); // #1
  97 
  98             // Enter lock a without blocking
  99             synchronized (a) {
 100                 p.arriveAndAwaitAdvance(); // #2
 101 
 102                 // Block to enter blockedObj1
 103                 // blockedObj1 should be owned by BlockingThread
 104                 synchronized (blockedObj1) {
 105                     accumulator++; // filler
 106                 }
 107             }
 108 
 109             // Enter lock a without blocking
 110             synchronized (b) {
 111                 // wait until BlockingThread holds blockedObj2
 112                 p.arriveAndAwaitAdvance(); // #3
 113 
 114                 // Block to enter blockedObj2
 115                 // blockedObj2 should be owned by BlockingThread
 116                 synchronized (blockedObj2) {
 117                     accumulator++; // filler
 118                 }
 119             }
 120 
 121             // Enter lock a without blocking
 122             synchronized (c) {
 123                 // wait until BlockingThread holds blockedObj3
 124                 p.arriveAndAwaitAdvance(); // #4
 125 
 126                 // Block to enter blockedObj3
 127                 // blockedObj3 should be owned by BlockingThread
 128                 synchronized (blockedObj3) {
 129                     accumulator++; // filler
 130                 }
 131             }
 132 
 133             // wait for the main thread to check the blocked count
 134             System.out.println("Acquired " + accumulator + " monitors");
 135             p.arriveAndAwaitAdvance(); // #5
 136             // ... and we can leave now
 137         } // run()
 138     } // BlockedThread
 139 
 140     static class BlockingThread extends Thread {
 141         private final Phaser p;
 142 
 143         BlockingThread(Phaser p) {
 144             super("BlockingThread");
 145             this.p = p;
 146         }
 147 
 148         private void waitForBlocked() {
 149             // wait for BlockedThread.
 150             p.arriveAndAwaitAdvance();
 151 
 152             boolean threadBlocked = false;
 153             while (!threadBlocked) {
 154                 // give a chance for BlockedThread to really block
 155                 try {
 156                     Thread.sleep(50);
 157                 } catch (InterruptedException e) {
 158                     System.err.println("Unexpected exception.");
 159                     e.printStackTrace(System.err);
 160                     testOk = false;
 161                     break;
 162                 }
 163                 ThreadInfo info = mbean.getThreadInfo(blocked.getId());
 164                 threadBlocked = (info.getThreadState() == Thread.State.BLOCKED);
 165             }
 166         }
 167 
 168         public void run() {
 169             p.arriveAndAwaitAdvance(); // #1
 170 
 171             synchronized (blockedObj1) {
 172                 System.out.println("BlockingThread attempts to notify a");
 173                 waitForBlocked(); // #2
 174             }
 175 
 176             // block until BlockedThread is ready
 177             synchronized (blockedObj2) {
 178                 System.out.println("BlockingThread attempts to notify b");
 179                 waitForBlocked(); // #3
 180             }
 181 
 182             // block until BlockedThread is ready
 183             synchronized (blockedObj3) {
 184                 System.out.println("BlockingThread attempts to notify c");
 185                 waitForBlocked(); // #4
 186             }
 187 
 188         } // run()
 189     } // BlockingThread
 190 
 191     private static long getBlockedCount() {
 192         long count;
 193         // Check the mbean now
 194         ThreadInfo ti = mbean.getThreadInfo(blocked.getId());
 195         count = ti.getBlockedCount();
 196         return count;
 197     }
 198 
 199     private static boolean checkBlocked() {
 200         // wait for the thread stats to be updated for 10 seconds
 201         long count = -1;
 202         for (int i = 0; i < 100; i++) {
 203             count = getBlockedCount();
 204             if (count >= EXPECTED_BLOCKED_COUNT) {
 205                 return true;
 206             }
 207             try {
 208                 Thread.sleep(100);
 209             } catch (InterruptedException e) {
 210                 System.err.println("Unexpected exception.");
 211                 e.printStackTrace(System.err);
 212                 return false;
 213             }
 214         }
 215         System.err.println("TEST FAILED: Blocked thread has " + count +
 216                             " blocked counts. Expected at least " +
 217                             EXPECTED_BLOCKED_COUNT);
 218         return false;
 219     }
 220 }