1 /*
   2  * Copyright (c) 2003, 2013, 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  * @run main ThreadBlockedCount
  31  */
  32 
  33 import java.lang.management.*;
  34 import java.util.concurrent.Phaser;
  35 
  36 public class ThreadBlockedCount {
  37         final static long EXPECTED_BLOCKED_COUNT = 3;
  38     final static int  DEPTH = 10;
  39     private static final ThreadMXBean mbean
  40         = ManagementFactory.getThreadMXBean();
  41 
  42     private static final Object a = new Object();
  43     private static final Object b = new Object();
  44     private static final Object c = new Object();
  45 
  46     private static final Object blockedObj1 = new Object();
  47     private static final Object blockedObj2 = new Object();
  48     private static final Object blockedObj3 = new Object();
  49     private static volatile boolean testOk = true;
  50     private static BlockingThread blocking;
  51     private static BlockedThread blocked;
  52 
  53     public static void main(String args[]) throws Exception {
  54         // real run
  55         runTest();
  56         if (!testOk) {
  57             throw new RuntimeException("TEST FAILED.");
  58         }
  59         System.out.println("Test passed.");
  60     }
  61 
  62     private static void runTest() throws Exception {
  63         final Phaser p = new Phaser(2);
  64 
  65         blocking = new BlockingThread(p);
  66         blocking.start();
  67 
  68         blocked = new BlockedThread(p);
  69         blocked.start();
  70 
  71         try {
  72             blocking.join();
  73 
  74             testOk = checkBlocked();
  75             p.arriveAndAwaitAdvance(); // #5
  76 
  77         } catch (InterruptedException e) {
  78             System.err.println("Unexpected exception.");
  79             e.printStackTrace(System.err);
  80             throw e;
  81         }
  82     }
  83 
  84 
  85     static class BlockedThread extends Thread {
  86         private final Phaser p;
  87 
  88         BlockedThread(Phaser p) {
  89             super("BlockedThread");
  90             this.p = p;
  91         }
  92 
  93         public void run() {
  94             int accumulator = 0;
  95             p.arriveAndAwaitAdvance(); // #1
  96 
  97             // Enter lock a without blocking
  98             synchronized (a) {
  99                 p.arriveAndAwaitAdvance(); // #2
 100 
 101                 // Block to enter blockedObj1
 102                 // blockedObj1 should be owned by BlockingThread
 103                 synchronized (blockedObj1) {
 104                     accumulator++; // filler
 105                 }
 106             }
 107 
 108             // Enter lock a without blocking
 109             synchronized (b) {
 110                 // wait until BlockingThread holds blockedObj2
 111                 p.arriveAndAwaitAdvance(); // #3
 112 
 113                 // Block to enter blockedObj2
 114                 // blockedObj2 should be owned by BlockingThread
 115                 synchronized (blockedObj2) {
 116                     accumulator++; // filler
 117                 }
 118             }
 119 
 120             // Enter lock a without blocking
 121             synchronized (c) {
 122                 // wait until BlockingThread holds blockedObj3
 123                 p.arriveAndAwaitAdvance(); // #4
 124 
 125                 // Block to enter blockedObj3
 126                 // blockedObj3 should be owned by BlockingThread
 127                 synchronized (blockedObj3) {
 128                     accumulator++; // filler
 129                 }
 130             }
 131 
 132             // wait for the main thread to check the blocked count
 133             System.out.println("Acquired " + accumulator + " monitors");
 134             p.arriveAndAwaitAdvance(); // #5
 135             // ... and we can leave now
 136         } // run()
 137     } // BlockedThread
 138 
 139     static class BlockingThread extends Thread {
 140         private final Phaser p;
 141 
 142         BlockingThread(Phaser p) {
 143             super("BlockingThread");
 144             this.p = p;
 145         }
 146 
 147         private void waitForBlocked() {
 148             // wait for BlockedThread.
 149             p.arriveAndAwaitAdvance();
 150 
 151             boolean threadBlocked = false;
 152             while (!threadBlocked) {
 153                 // give a chance for BlockedThread to really block
 154                 try {
 155                     Thread.sleep(50);
 156                 } catch (InterruptedException e) {
 157                     System.err.println("Unexpected exception.");
 158                     e.printStackTrace(System.err);
 159                     testOk = false;
 160                     break;
 161                 }
 162                 ThreadInfo info = mbean.getThreadInfo(blocked.getId());
 163                 threadBlocked = (info.getThreadState() == Thread.State.BLOCKED);
 164             }
 165         }
 166 
 167         public void run() {
 168             p.arriveAndAwaitAdvance(); // #1
 169 
 170             synchronized (blockedObj1) {
 171                 System.out.println("BlockingThread attempts to notify a");
 172                 waitForBlocked(); // #2
 173             }
 174 
 175             // block until BlockedThread is ready
 176             synchronized (blockedObj2) {
 177                 System.out.println("BlockingThread attempts to notify b");
 178                 waitForBlocked(); // #3
 179             }
 180 
 181             // block until BlockedThread is ready
 182             synchronized (blockedObj3) {
 183                 System.out.println("BlockingThread attempts to notify c");
 184                 waitForBlocked(); // #4
 185             }
 186 
 187         } // run()
 188     } // BlockingThread
 189 
 190     private static long getBlockedCount() {
 191         long count;
 192         // Check the mbean now
 193         ThreadInfo ti = mbean.getThreadInfo(blocked.getId());
 194         count = ti.getBlockedCount();
 195         return count;
 196     }
 197 
 198     private static boolean checkBlocked() {
 199         // wait for the thread stats to be updated for 10 seconds
 200         long count = -1;
 201         for (int i = 0; i < 100; i++) {
 202             count = getBlockedCount();
 203             if (count >= EXPECTED_BLOCKED_COUNT) {
 204                 return true;
 205             }
 206             try {
 207                 Thread.sleep(100);
 208             } catch (InterruptedException e) {
 209                 System.err.println("Unexpected exception.");
 210                 e.printStackTrace(System.err);
 211                 return false;
 212             }
 213         }
 214         System.err.println("TEST FAILED: Blocked thread has " + count +
 215                             " blocked counts. Expected at least " +
 216                             EXPECTED_BLOCKED_COUNT);
 217         return false;
 218     }
 219 }