/* * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @bug 4892507 8020875 8021335 * @summary Basic Test for the following reset methods: * - ThreadMXBean.resetPeakThreadCount() * @author Mandy Chung * @author Jaroslav Bachorik * * @build ResetPeakThreadCount * @build ThreadDump * @run main/othervm ResetPeakThreadCount */ import java.lang.management.*; public class ResetPeakThreadCount { // initial number of new threads started private static final int DAEMON_THREADS_1 = 8; private static final int EXPECTED_PEAK_DELTA_1 = 8; // Terminate half of the threads started private static final int TERMINATE_1 = 4; // start new threads but expected the peak unchanged private static final int DAEMON_THREADS_2 = 2; private static final int EXPECTED_PEAK_DELTA_2 = 0; // peak thread count reset before starting new threads private static final int DAEMON_THREADS_3 = 4; private static final int EXPECTED_PEAK_DELTA_3 = 4; private static final int TERMINATE_2 = 8; private static final int TERMINATE_3 = 2; private static final int ALL_THREADS = DAEMON_THREADS_1 + DAEMON_THREADS_2 + DAEMON_THREADS_3; // barrier for threads communication private static final Barrier barrier = new Barrier(DAEMON_THREADS_1); private static final Thread allThreads[] = new Thread[ALL_THREADS]; private static final boolean live[] = new boolean[ALL_THREADS]; private static final ThreadMXBean mbean = ManagementFactory.getThreadMXBean(); private static volatile boolean testFailed = false; public static void main(String[] argv) throws Exception { // This test does not expect any threads to be created // by the test harness after main() is invoked. // The checkThreadCount() method is to produce more // diagnostic information in case any unexpected test failure occur. long previous = mbean.getThreadCount(); long current = previous; // reset the peak to start from a scratch resetPeak(current); // start DAEMON_THREADS_1 number of threads current = startThreads(0, DAEMON_THREADS_1, EXPECTED_PEAK_DELTA_1); checkThreadCount(previous, current, DAEMON_THREADS_1); previous = current; // terminate TERMINATE_1 number of threads and reset peak current = terminateThreads(0, TERMINATE_1); checkThreadCount(previous, current, TERMINATE_1 * -1); previous = current; // start DAEMON_THREADS_2 number of threads // expected peak is unchanged current = startThreads(DAEMON_THREADS_1, DAEMON_THREADS_2, EXPECTED_PEAK_DELTA_2); checkThreadCount(previous, current, DAEMON_THREADS_2); previous = current; // Reset the peak resetPeak(current); // start DAEMON_THREADS_3 number of threads current = startThreads(DAEMON_THREADS_1 + DAEMON_THREADS_2, DAEMON_THREADS_3, EXPECTED_PEAK_DELTA_3); checkThreadCount(previous, current, DAEMON_THREADS_3); previous = current; // terminate TERMINATE_2 number of threads and reset peak current = terminateThreads(TERMINATE_1, TERMINATE_2); checkThreadCount(previous, current, TERMINATE_2 * -1); previous = current; resetPeak(current); // terminate TERMINATE_3 number of threads and reset peak current = terminateThreads(TERMINATE_1 + TERMINATE_2, TERMINATE_3); checkThreadCount(previous, current, TERMINATE_3 * -1); resetPeak(current); if (testFailed) throw new RuntimeException("TEST FAILED."); System.out.println("Test passed"); } private static long startThreads(int from, int count, int delta) throws InterruptedException { // get current peak thread count long peak1 = mbean.getPeakThreadCount(); long current = mbean.getThreadCount(); // Start threads and wait to be sure they all are alive System.out.println("Starting " + count + " threads...."); barrier.set(count); synchronized(live) { for (int i = from; i < (from + count); i++) { live[i] = true; allThreads[i] = new MyThread(i); allThreads[i].setDaemon(true); allThreads[i].start(); } } // wait until all threads have started. barrier.await(); // get peak thread count after daemon threads have started long peak2 = mbean.getPeakThreadCount(); System.out.println(" Current = " + mbean.getThreadCount() + " Peak before = " + peak1 + " after: " + peak2); if (peak2 != (peak1 + delta)) { throw new RuntimeException("Current Peak = " + peak2 + " Expected to be == previous peak = " + peak1 + " + " + delta); } // wait until the current thread count gets incremented while (mbean.getThreadCount() < (current + count)) { Thread.sleep(100); } current = mbean.getThreadCount(); System.out.println(" Live thread count before returns " + current); return current; } private static long terminateThreads(int from, int count) throws InterruptedException { // get current peak thread count long peak1 = mbean.getPeakThreadCount(); // Stop daemon threads and wait to be sure they all are dead System.out.println("Terminating " + count + " threads...."); barrier.set(count); synchronized(live) { for (int i = from; i < (from+count); i++) { live[i] = false; } live.notifyAll(); } // wait until daemon threads terminated. barrier.await(); // get peak thread count after daemon threads have terminated long peak2 = mbean.getPeakThreadCount(); // assuming no system thread is added if (peak2 != peak1) { throw new RuntimeException("Current Peak = " + peak2 + " Expected to be = previous peak = " + peak1); } for (int i = from; i < (from+count); i++) { allThreads[i].join(); } // there is a race in the counter update logic somewhere causing // the thread counters go ff // we need to give the terminated threads some extra time to really die // JDK-8021335 Thread.sleep(500); long current = mbean.getThreadCount(); System.out.println(" Live thread count before returns " + current); return current; } private static void resetPeak(long expectedCount) { long peak3 = mbean.getPeakThreadCount(); long current = mbean.getThreadCount(); // Nightly testing showed some intermittent failure. // Check here to get diagnostic information if some strange // behavior occurs. checkThreadCount(expectedCount, current, 0); // Reset peak thread count mbean.resetPeakThreadCount(); long afterResetPeak = mbean.getPeakThreadCount(); long afterResetCurrent = mbean.getThreadCount(); System.out.println("Reset peak before = " + peak3 + " current = " + current + " after reset peak = " + afterResetPeak + " current = " + afterResetCurrent); if (afterResetPeak != current) { throw new RuntimeException("Current Peak after reset = " + afterResetPeak + " Expected to be = current count = " + current); } } private static void checkThreadCount(long previous, long current, int expectedDelta) { if (current != previous + expectedDelta) { ThreadDump.threadDump(); throw new RuntimeException("***** Unexpected thread count:" + " previous = " + previous + " current = " + current + " delta = " + expectedDelta + "*****"); } } // The MyThread thread lives as long as correspondent live[i] value is true private static class MyThread extends Thread { int id; MyThread(int id) { this.id = id; } public void run() { // signal started barrier.signal(); synchronized(live) { while (live[id]) { try { live.wait(100); } catch (InterruptedException e) { System.out.println("Unexpected exception is thrown."); e.printStackTrace(System.out); testFailed = true; } } } // signal about to exit barrier.signal(); } } }