8262001: java/lang/management/ThreadMXBean/ResetPeakThreadCount.java failed with "RuntimeException: Current Peak = 14 Expected to be == previous peak = 7 + 8"
Reviewed-by: dfuchs, sspitsyn
This commit is contained in:
parent
01ddf3d280
commit
c82a673cf6
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2021, 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
|
||||
@ -35,218 +35,177 @@
|
||||
*/
|
||||
|
||||
import java.lang.management.*;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
private static final int DAEMON_THREADS_1 = 80;
|
||||
|
||||
// Terminate half of the threads started
|
||||
private static final int TERMINATE_1 = 4;
|
||||
private static final int TERMINATE_1 = 40;
|
||||
|
||||
// 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;
|
||||
private static final int DAEMON_THREADS_2 = 20;
|
||||
|
||||
// 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 DAEMON_THREADS_3 = 20;
|
||||
|
||||
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;
|
||||
|
||||
private static final List<MyThread> threads = new LinkedList<>();
|
||||
private static final Object liveSync = new Object();
|
||||
|
||||
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;
|
||||
// System threads can be started/terminated during the test execution,
|
||||
// and they affect resetPeakThreadCount result.
|
||||
resetPeak();
|
||||
|
||||
// reset the peak to start from a scratch
|
||||
resetPeak(current);
|
||||
startThreads(DAEMON_THREADS_1);
|
||||
|
||||
// start DAEMON_THREADS_1 number of threads
|
||||
current = startThreads(0, DAEMON_THREADS_1, EXPECTED_PEAK_DELTA_1);
|
||||
int beforeTerminate = checkPeakThreadCount(threads.size() + 1, -1); // + 1 for the current thread
|
||||
|
||||
checkThreadCount(previous, current, DAEMON_THREADS_1);
|
||||
previous = current;
|
||||
terminateThreads(TERMINATE_1);
|
||||
|
||||
// terminate TERMINATE_1 number of threads and reset peak
|
||||
current = terminateThreads(0, TERMINATE_1);
|
||||
// the value should not decrease
|
||||
int afterTerminate = checkPeakThreadCount(beforeTerminate, -1);
|
||||
|
||||
checkThreadCount(previous, current, TERMINATE_1 * -1);
|
||||
startThreads(DAEMON_THREADS_2);
|
||||
|
||||
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);
|
||||
checkPeakThreadCount(-1, afterTerminate);
|
||||
|
||||
checkThreadCount(previous, current, DAEMON_THREADS_2);
|
||||
previous = current;
|
||||
// reset peak and ensure new threads increase the value
|
||||
int beforeThreads3 = resetPeak();
|
||||
startThreads(DAEMON_THREADS_3);
|
||||
|
||||
// Reset the peak
|
||||
resetPeak(current);
|
||||
checkPeakThreadCount(threads.size() + 1, -1); // + 1 for the current thread
|
||||
checkPeakThreadCount(beforeThreads3, -1);
|
||||
|
||||
// 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)
|
||||
if (testFailed) {
|
||||
throw new RuntimeException("TEST FAILED.");
|
||||
}
|
||||
|
||||
System.out.println("Test passed");
|
||||
}
|
||||
|
||||
private static long startThreads(int from, int count, int delta) throws InterruptedException {
|
||||
private static void startThreads(int count) throws InterruptedException {
|
||||
// get current peak thread count
|
||||
long peak1 = mbean.getPeakThreadCount();
|
||||
long current = mbean.getThreadCount();
|
||||
int peak1 = mbean.getPeakThreadCount();
|
||||
|
||||
// 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();
|
||||
synchronized (liveSync) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
MyThread newThread = new MyThread();
|
||||
threads.add(newThread);
|
||||
newThread.start();
|
||||
}
|
||||
}
|
||||
// wait until all threads have started.
|
||||
barrier.await();
|
||||
|
||||
// get peak thread count after daemon threads have started
|
||||
long peak2 = mbean.getPeakThreadCount();
|
||||
int 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);
|
||||
}
|
||||
current = mbean.getThreadCount();
|
||||
int current = mbean.getThreadCount();
|
||||
System.out.println(" Live thread count before returns " + current);
|
||||
return current;
|
||||
}
|
||||
|
||||
private static long terminateThreads(int from, int count) throws InterruptedException {
|
||||
private static void terminateThreads(int count) throws InterruptedException {
|
||||
// get current peak thread count
|
||||
long peak1 = mbean.getPeakThreadCount();
|
||||
int 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;
|
||||
synchronized(liveSync) {
|
||||
Iterator<MyThread> iter = threads.iterator();
|
||||
for (int i = 0; i < count; i++) {
|
||||
MyThread thread = iter.next();
|
||||
thread.live = false;
|
||||
}
|
||||
live.notifyAll();
|
||||
liveSync.notifyAll();
|
||||
}
|
||||
// wait until daemon threads terminated.
|
||||
barrier.await();
|
||||
|
||||
// get peak thread count after daemon threads have terminated
|
||||
long peak2 = mbean.getPeakThreadCount();
|
||||
int 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();
|
||||
for (int i = 0; i < count; i++) {
|
||||
MyThread thread = threads.remove(0);
|
||||
thread.join();
|
||||
}
|
||||
|
||||
long current = mbean.getThreadCount();
|
||||
int 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);
|
||||
// Returns peak thread value after reset.
|
||||
private static int resetPeak() {
|
||||
int peak3 = mbean.getPeakThreadCount();
|
||||
int current = mbean.getThreadCount();
|
||||
|
||||
// Reset peak thread count
|
||||
mbean.resetPeakThreadCount();
|
||||
|
||||
long afterResetPeak = mbean.getPeakThreadCount();
|
||||
long afterResetCurrent = mbean.getThreadCount();
|
||||
int afterResetPeak = mbean.getPeakThreadCount();
|
||||
int 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);
|
||||
}
|
||||
return afterResetPeak;
|
||||
}
|
||||
|
||||
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 + "*****");
|
||||
}
|
||||
private static void fail(String msg) {
|
||||
ThreadDump.threadDump();
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
// The MyThread thread lives as long as correspondent live[i] value is true
|
||||
private static int checkPeakThreadCount(int min, int max) {
|
||||
int value = mbean.getPeakThreadCount();
|
||||
if (min > 0 && value < min) {
|
||||
fail("***** Unexpected thread count: " + value + ", minimum expected " + min + " *****");
|
||||
}
|
||||
if (max > 0 && value > max) {
|
||||
fail("***** Unexpected thread count: " + value + ", maximum expected " + max + " *****");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
// The MyThread thread lives as long as correspondent its live value is true.
|
||||
private static class MyThread extends Thread {
|
||||
int id;
|
||||
volatile boolean live;
|
||||
|
||||
MyThread(int id) {
|
||||
this.id = id;
|
||||
MyThread() {
|
||||
live = true;
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
// signal started
|
||||
barrier.signal();
|
||||
synchronized(live) {
|
||||
while (live[id]) {
|
||||
synchronized(liveSync) {
|
||||
while (live) {
|
||||
try {
|
||||
live.wait(100);
|
||||
liveSync.wait(100);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Unexpected exception is thrown.");
|
||||
e.printStackTrace(System.out);
|
||||
|
Loading…
Reference in New Issue
Block a user