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 ThreadMXBean.getAllThreadIds()
  28  * @author  Alexei Guibadoulline and Mandy Chung
  29  *
  30  * @modules java.management
  31  * @run main/othervm AllThreadIds
  32  */
  33 
  34 import java.lang.management.*;
  35 import java.util.concurrent.Phaser;
  36 
  37 public class AllThreadIds {
  38     final static int DAEMON_THREADS = 20;
  39     final static int USER_THREADS = 5;
  40     final static int ALL_THREADS = DAEMON_THREADS + USER_THREADS;
  41     private static final boolean live[] = new boolean[ALL_THREADS];
  42     private static final Thread allThreads[] = new Thread[ALL_THREADS];
  43     private static final ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
  44     private static boolean testFailed = false;
  45     private static boolean trace = false;
  46 
  47     private static long prevTotalThreadCount = 0;
  48     private static int prevLiveThreadCount = 0;
  49     private static int prevPeakThreadCount = 0;
  50     private static long curTotalThreadCount = 0;
  51     private static int curLiveThreadCount = 0;
  52     private static int curPeakThreadCount = 0;
  53 
  54     private static final Phaser startupCheck = new Phaser(ALL_THREADS + 1);
  55 
  56     private static void printThreadList() {
  57         if (!trace) return;
  58 
  59         long[] list = mbean.getAllThreadIds();
  60         for (int i = 1; i <= list.length; i++) {
  61             System.out.println(i + ": Thread id = " + list[i-1]);
  62         }
  63         for (int i = 0; i < ALL_THREADS; i++) {
  64             Thread t = allThreads[i];
  65             System.out.println(t.getName() + " Id = " + t.getId() +
  66                 " die = " + live[i] +
  67                 " alive = " + t.isAlive());
  68         }
  69     }
  70 
  71     private static void fail(String msg) {
  72         trace = true;
  73         printThreadList();
  74         throw new RuntimeException(msg);
  75     }
  76 
  77     private static void checkThreadCount(int numNewThreads,
  78                                          int numTerminatedThreads)
  79         throws Exception {
  80         prevTotalThreadCount = curTotalThreadCount;
  81         prevLiveThreadCount = curLiveThreadCount;
  82         prevPeakThreadCount = curPeakThreadCount;
  83         curTotalThreadCount = mbean.getTotalStartedThreadCount();
  84         curLiveThreadCount = mbean.getThreadCount();
  85         curPeakThreadCount = mbean.getPeakThreadCount();
  86 
  87         if ((curLiveThreadCount - prevLiveThreadCount) !=
  88             (numNewThreads - numTerminatedThreads)) {
  89             fail("Unexpected number of live threads: " +
  90                 " Prev live = " + prevLiveThreadCount +
  91                 " Current live = " + curLiveThreadCount +
  92                 " Threads added = " + numNewThreads +
  93                 " Threads terminated = " + numTerminatedThreads);
  94         }
  95         if (curPeakThreadCount - prevPeakThreadCount != numNewThreads) {
  96             fail("Unexpected number of peak threads: " +
  97                 " Prev peak = " + prevPeakThreadCount +
  98                 " Current peak = " + curPeakThreadCount +
  99                 " Threads added = " + numNewThreads);
 100         }
 101         if (curTotalThreadCount - prevTotalThreadCount != numNewThreads) {
 102             fail("Unexpected number of total threads: " +
 103                 " Prev Total = " + prevTotalThreadCount +
 104                 " Current Total = " + curTotalThreadCount +
 105                 " Threads added = " + numNewThreads);
 106         }
 107         long[] list = mbean.getAllThreadIds();
 108         if (list.length != curLiveThreadCount) {
 109             fail("Array length returned by " +
 110                 "getAllThreadIds() = " + list.length +
 111                 " not matched count = " + curLiveThreadCount);
 112         }
 113     }
 114 
 115     public static void main(String args[]) throws Exception {
 116         if (args.length > 0 && args[0].equals("trace")) {
 117             trace = true;
 118         }
 119 
 120         curTotalThreadCount = mbean.getTotalStartedThreadCount();
 121         curLiveThreadCount = mbean.getThreadCount();
 122         curPeakThreadCount = mbean.getPeakThreadCount();
 123         checkThreadCount(0, 0);
 124 
 125         // Start all threads and wait to be sure they all are alive
 126         for (int i = 0; i < ALL_THREADS; i++) {
 127             setLive(i, true);
 128             allThreads[i] = new MyThread(i);
 129             allThreads[i].setDaemon(i < DAEMON_THREADS);
 130             allThreads[i].start();
 131         }
 132         // wait until all threads are started.
 133         startupCheck.arriveAndAwaitAdvance();
 134 
 135         checkThreadCount(ALL_THREADS, 0);
 136         printThreadList();
 137 
 138         // Check mbean now. All threads must appear in getAllThreadIds() list
 139         long[] list = mbean.getAllThreadIds();
 140 
 141         for (int i = 0; i < ALL_THREADS; i++) {
 142             long expectedId = allThreads[i].getId();
 143             boolean found = false;
 144 
 145             if (trace) {
 146                 System.out.print("Looking for thread with id " + expectedId);
 147             }
 148             for (int j = 0; j < list.length; j++) {
 149                 if (expectedId == list[j]) {
 150                     found = true;
 151                     break;
 152                 }
 153             }
 154 
 155             if (!found) {
 156                 testFailed = true;
 157             }
 158             if (trace) {
 159                 if (!found) {
 160                     System.out.print(". TEST FAILED.");
 161                 }
 162                 System.out.println();
 163             }
 164         }
 165         if (trace) {
 166             System.out.println();
 167         }
 168 
 169         // Stop daemon threads, wait to be sure they all are dead, and check
 170         // that they disappeared from getAllThreadIds() list
 171         for (int i = 0; i < DAEMON_THREADS; i++) {
 172             setLive(i, false);
 173         }
 174 
 175         // make sure the daemon threads are completely dead
 176         joinDaemonThreads();
 177 
 178         // and check the reported thread count
 179         checkThreadCount(0, DAEMON_THREADS);
 180 
 181         // Check mbean now
 182         list = mbean.getAllThreadIds();
 183 
 184         for (int i = 0; i < ALL_THREADS; i++) {
 185             long expectedId = allThreads[i].getId();
 186             boolean found = false;
 187             boolean alive = (i >= DAEMON_THREADS);
 188 
 189             if (trace) {
 190                 System.out.print("Looking for thread with id " + expectedId +
 191                     (alive ? " expected alive." : " expected terminated."));
 192             }
 193             for (int j = 0; j < list.length; j++) {
 194                 if (expectedId == list[j]) {
 195                     found = true;
 196                     break;
 197                 }
 198             }
 199 
 200             if (alive != found) {
 201                 testFailed = true;
 202             }
 203             if (trace) {
 204                 if (alive != found) {
 205                     System.out.println(" TEST FAILED.");
 206                 } else {
 207                     System.out.println();
 208                 }
 209             }
 210         }
 211 
 212         // Stop all threads and wait to be sure they all are dead
 213         for (int i = DAEMON_THREADS; i < ALL_THREADS; i++) {
 214             setLive(i, false);
 215         }
 216 
 217         // make sure the non-daemon threads are completely dead
 218         joinNonDaemonThreads();
 219 
 220         // and check the thread count
 221         checkThreadCount(0, ALL_THREADS - DAEMON_THREADS);
 222 
 223         if (testFailed)
 224             throw new RuntimeException("TEST FAILED.");
 225 
 226         System.out.println("Test passed.");
 227     }
 228 
 229     private static void joinDaemonThreads() throws InterruptedException {
 230         for (int i = 0; i < DAEMON_THREADS; i++) {
 231             allThreads[i].join();
 232         }
 233     }
 234 
 235     private static void joinNonDaemonThreads() throws InterruptedException {
 236         for (int i = DAEMON_THREADS; i < ALL_THREADS; i++) {
 237             allThreads[i].join();
 238         }
 239     }
 240 
 241     private static void setLive(int i, boolean val) {
 242         synchronized(live) {
 243             live[i] = val;
 244         }
 245     }
 246 
 247     private static boolean isLive(int i) {
 248         synchronized(live) {
 249             return live[i];
 250         }
 251     }
 252 
 253     // The MyThread thread lives as long as correspondent live[i] value is true
 254     private static class MyThread extends Thread {
 255         int id;
 256 
 257         MyThread(int id) {
 258             this.id = id;
 259         }
 260 
 261         public void run() {
 262             // signal started
 263             startupCheck.arrive();
 264             while (isLive(id)) {
 265                 try {
 266                     sleep(100);
 267                 } catch (InterruptedException e) {
 268                     System.out.println("Unexpected exception is thrown.");
 269                     e.printStackTrace(System.out);
 270                     testFailed = true;
 271                 }
 272             }
 273         }
 274     }
 275 }