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