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 
main(String[] argv)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 
startThreads(int from, int count, int delta)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         current = mbean.getThreadCount();
162         System.out.println("   Live thread count before returns " + current);
163         return current;
164     }
165 
terminateThreads(int from, int count)166     private static long terminateThreads(int from, int count) throws InterruptedException {
167         // get current peak thread count
168         long peak1 = mbean.getPeakThreadCount();
169 
170         // Stop daemon threads and wait to be sure they all are dead
171         System.out.println("Terminating " + count + " threads....");
172         barrier.set(count);
173         synchronized(live) {
174             for (int i = from; i < (from+count); i++) {
175                 live[i] = false;
176             }
177             live.notifyAll();
178         }
179         // wait until daemon threads terminated.
180         barrier.await();
181 
182         // get peak thread count after daemon threads have terminated
183         long peak2 = mbean.getPeakThreadCount();
184         // assuming no system thread is added
185         if (peak2 != peak1) {
186             throw new RuntimeException("Current Peak = " + peak2 +
187                 " Expected to be = previous peak = " + peak1);
188         }
189 
190         for (int i = from; i < (from+count); i++) {
191             allThreads[i].join();
192         }
193 
194         long current = mbean.getThreadCount();
195         System.out.println("   Live thread count before returns " + current);
196         return current;
197     }
198 
resetPeak(long expectedCount)199     private static void resetPeak(long expectedCount) {
200         long peak3 = mbean.getPeakThreadCount();
201         long current = mbean.getThreadCount();
202 
203         // Nightly testing showed some intermittent failure.
204         // Check here to get diagnostic information if some strange
205         // behavior occurs.
206         checkThreadCount(expectedCount, current, 0);
207 
208         // Reset peak thread count
209         mbean.resetPeakThreadCount();
210 
211         long afterResetPeak = mbean.getPeakThreadCount();
212         long afterResetCurrent = mbean.getThreadCount();
213         System.out.println("Reset peak before = " + peak3 +
214             " current = " + current +
215             " after reset peak = " + afterResetPeak +
216             " current = " + afterResetCurrent);
217 
218         if (afterResetPeak != current) {
219             throw new RuntimeException("Current Peak after reset = " +
220                 afterResetPeak +
221                 " Expected to be = current count = " + current);
222         }
223     }
224 
checkThreadCount(long previous, long current, int expectedDelta)225     private static void checkThreadCount(long previous, long current, int expectedDelta) {
226         if (current != previous + expectedDelta) {
227             ThreadDump.threadDump();
228             throw new RuntimeException("***** Unexpected thread count:" +
229                                " previous = " + previous +
230                                " current = " + current +
231                                " delta = " + expectedDelta + "*****");
232         }
233     }
234 
235     // The MyThread thread lives as long as correspondent live[i] value is true
236     private static class MyThread extends Thread {
237         int id;
238 
MyThread(int id)239         MyThread(int id) {
240             this.id = id;
241         }
242 
run()243         public void run() {
244             // signal started
245             barrier.signal();
246             synchronized(live) {
247                 while (live[id]) {
248                     try {
249                         live.wait(100);
250                     } catch (InterruptedException e) {
251                         System.out.println("Unexpected exception is thrown.");
252                         e.printStackTrace(System.out);
253                         testFailed = true;
254                     }
255                 }
256             }
257             // signal about to exit
258             barrier.signal();
259         }
260     }
261 
262 }
263