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 4892507 8020875 8021335 27 * @summary Basic Test for the following reset methods: 28 * - ThreadMXBean.resetPeakThreadCount() 29 * @author Mandy Chung 30 * @author Jaroslav Bachorik 31 * 32 * @build ResetPeakThreadCount 33 * @build ThreadDump 34 * @run main/othervm ResetPeakThreadCount 35 */ 36 37 import java.lang.management.*; 38 39 public class ResetPeakThreadCount { 40 // initial number of new threads started 41 private static final int DAEMON_THREADS_1 = 8; 42 private static final int EXPECTED_PEAK_DELTA_1 = 8; 43 44 // Terminate half of the threads started 45 private static final int TERMINATE_1 = 4; 46 47 // start new threads but expected the peak unchanged 48 private static final int DAEMON_THREADS_2 = 2; 49 private static final int EXPECTED_PEAK_DELTA_2 = 0; 50 51 // peak thread count reset before starting new threads 52 private static final int DAEMON_THREADS_3 = 4; 53 private static final int EXPECTED_PEAK_DELTA_3 = 4; 54 55 private static final int TERMINATE_2 = 8; 56 57 private static final int TERMINATE_3 = 2; 58 59 private static final int ALL_THREADS = DAEMON_THREADS_1 + 60 DAEMON_THREADS_2 + DAEMON_THREADS_3; 61 // barrier for threads communication 62 private static final Barrier barrier = new Barrier(DAEMON_THREADS_1); 63 64 private static final Thread allThreads[] = new Thread[ALL_THREADS]; 65 private static final boolean live[] = new boolean[ALL_THREADS]; 66 private static final ThreadMXBean mbean = ManagementFactory.getThreadMXBean(); 67 private static volatile boolean testFailed = false; 68 69 public static void main(String[] argv) throws Exception { 70 // This test does not expect any threads to be created 71 // by the test harness after main() is invoked. 72 // The checkThreadCount() method is to produce more 73 // diagnostic information in case any unexpected test failure occur. 74 long previous = mbean.getThreadCount(); 75 long current = previous; 76 77 // reset the peak to start from a scratch 78 resetPeak(current); 79 80 // start DAEMON_THREADS_1 number of threads 81 current = startThreads(0, DAEMON_THREADS_1, EXPECTED_PEAK_DELTA_1); 82 83 checkThreadCount(previous, current, DAEMON_THREADS_1); 84 previous = current; 85 86 // terminate TERMINATE_1 number of threads and reset peak 87 current = terminateThreads(0, TERMINATE_1); 88 89 checkThreadCount(previous, current, TERMINATE_1 * -1); 90 91 previous = current; 92 93 // start DAEMON_THREADS_2 number of threads 94 // expected peak is unchanged 95 current = startThreads(DAEMON_THREADS_1, DAEMON_THREADS_2, 96 EXPECTED_PEAK_DELTA_2); 97 98 checkThreadCount(previous, current, DAEMON_THREADS_2); 99 previous = current; 100 101 // Reset the peak 102 resetPeak(current); 103 104 // start DAEMON_THREADS_3 number of threads 105 current = startThreads(DAEMON_THREADS_1 + DAEMON_THREADS_2, 106 DAEMON_THREADS_3, EXPECTED_PEAK_DELTA_3); 107 108 checkThreadCount(previous, current, DAEMON_THREADS_3); 109 previous = current; 110 111 // terminate TERMINATE_2 number of threads and reset peak 112 current = terminateThreads(TERMINATE_1, TERMINATE_2); 113 114 checkThreadCount(previous, current, TERMINATE_2 * -1); 115 previous = current; 116 117 resetPeak(current); 118 119 // terminate TERMINATE_3 number of threads and reset peak 120 current = terminateThreads(TERMINATE_1 + TERMINATE_2, TERMINATE_3); 121 122 checkThreadCount(previous, current, TERMINATE_3 * -1); 123 resetPeak(current); 124 125 if (testFailed) 126 throw new RuntimeException("TEST FAILED."); 127 128 System.out.println("Test passed"); 129 } 130 131 private static long startThreads(int from, int count, int delta) throws InterruptedException { 132 // get current peak thread count 133 long peak1 = mbean.getPeakThreadCount(); 134 long current = mbean.getThreadCount(); 135 136 // Start threads and wait to be sure they all are alive 137 System.out.println("Starting " + count + " threads...."); 138 barrier.set(count); 139 synchronized(live) { 140 for (int i = from; i < (from + count); i++) { 141 live[i] = true; 142 allThreads[i] = new MyThread(i); 143 allThreads[i].setDaemon(true); 144 allThreads[i].start(); 145 } 146 } 147 // wait until all threads have started. 148 barrier.await(); 149 150 // get peak thread count after daemon threads have started 151 long peak2 = mbean.getPeakThreadCount(); 152 153 System.out.println(" Current = " + mbean.getThreadCount() + 154 " Peak before = " + peak1 + " after: " + peak2); 155 156 if (peak2 != (peak1 + delta)) { 157 throw new RuntimeException("Current Peak = " + peak2 + 158 " Expected to be == previous peak = " + peak1 + " + " + 159 delta); 160 } 161 // wait until the current thread count gets incremented 162 while (mbean.getThreadCount() < (current + count)) { 163 Thread.sleep(100); 164 } 165 current = mbean.getThreadCount(); 166 System.out.println(" Live thread count before returns " + current); 167 return current; 168 } 169 170 private static long terminateThreads(int from, int count) throws InterruptedException { 171 // get current peak thread count 172 long peak1 = mbean.getPeakThreadCount(); 173 174 // Stop daemon threads and wait to be sure they all are dead 175 System.out.println("Terminating " + count + " threads...."); 176 barrier.set(count); 177 synchronized(live) { 178 for (int i = from; i < (from+count); i++) { 179 live[i] = false; 180 } 181 live.notifyAll(); 182 } 183 // wait until daemon threads terminated. 184 barrier.await(); 185 186 // get peak thread count after daemon threads have terminated 187 long peak2 = mbean.getPeakThreadCount(); 188 // assuming no system thread is added 189 if (peak2 != peak1) { 190 throw new RuntimeException("Current Peak = " + peak2 + 191 " Expected to be = previous peak = " + peak1); 192 } 193 194 for (int i = from; i < (from+count); i++) { 195 allThreads[i].join(); 196 } 197 198 // there is a race in the counter update logic somewhere causing 199 // the thread counters go ff 200 // we need to give the terminated threads some extra time to really die 201 // JDK-8021335 202 Thread.sleep(500); 203 204 long current = mbean.getThreadCount(); 205 System.out.println(" Live thread count before returns " + current); 206 return current; 207 } 208 209 private static void resetPeak(long expectedCount) { 210 long peak3 = mbean.getPeakThreadCount(); 211 long current = mbean.getThreadCount(); 212 213 // Nightly testing showed some intermittent failure. 214 // Check here to get diagnostic information if some strange 215 // behavior occurs. 216 checkThreadCount(expectedCount, current, 0); 217 218 // Reset peak thread count 219 mbean.resetPeakThreadCount(); 220 221 long afterResetPeak = mbean.getPeakThreadCount(); 222 long afterResetCurrent = mbean.getThreadCount(); 223 System.out.println("Reset peak before = " + peak3 + 224 " current = " + current + 225 " after reset peak = " + afterResetPeak + 226 " current = " + afterResetCurrent); 227 228 if (afterResetPeak != current) { 229 throw new RuntimeException("Current Peak after reset = " + 230 afterResetPeak + 231 " Expected to be = current count = " + current); 232 } 233 } 234 235 private static void checkThreadCount(long previous, long current, int expectedDelta) { 236 if (current != previous + expectedDelta) { 237 ThreadDump.threadDump(); 238 throw new RuntimeException("***** Unexpected thread count:" + 239 " previous = " + previous + 240 " current = " + current + 241 " delta = " + expectedDelta + "*****"); 242 } 243 } 244 245 // The MyThread thread lives as long as correspondent live[i] value is true 246 private static class MyThread extends Thread { 247 int id; 248 249 MyThread(int id) { 250 this.id = id; 251 } 252 253 public void run() { 254 // signal started 255 barrier.signal(); 256 synchronized(live) { 257 while (live[id]) { 258 try { 259 live.wait(100); 260 } catch (InterruptedException e) { 261 System.out.println("Unexpected exception is thrown."); 262 e.printStackTrace(System.out); 263 testFailed = true; 264 } 265 } 266 } 267 // signal about to exit 268 barrier.signal(); 269 } 270 } 271 272 }