Skip to content
Permalink
Browse files
8262001: java/lang/management/ThreadMXBean/ResetPeakThreadCount.java …
…failed with "RuntimeException: Current Peak = 14 Expected to be == previous peak = 7 + 8"

Reviewed-by: dfuchs, sspitsyn
  • Loading branch information
Alex Menkov committed Mar 18, 2021
1 parent 01ddf3d commit c82a673cf6124d38fadf33a8ed6650620e263477
Showing with 78 additions and 119 deletions.
  1. +78 −119 test/jdk/java/lang/management/ThreadMXBean/ResetPeakThreadCount.java
@@ -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;

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;
private static final List<MyThread> threads = new LinkedList<>();
private static final Object liveSync = new Object();

// reset the peak to start from a scratch
resetPeak(current);
public static void main(String[] argv) throws Exception {
// System threads can be started/terminated during the test execution,
// and they affect resetPeakThreadCount result.
resetPeak();

// start DAEMON_THREADS_1 number of threads
current = startThreads(0, DAEMON_THREADS_1, EXPECTED_PEAK_DELTA_1);
startThreads(DAEMON_THREADS_1);

checkThreadCount(previous, current, DAEMON_THREADS_1);
previous = current;
int beforeTerminate = checkPeakThreadCount(threads.size() + 1, -1); // + 1 for the current thread

// terminate TERMINATE_1 number of threads and reset peak
current = terminateThreads(0, TERMINATE_1);
terminateThreads(TERMINATE_1);

checkThreadCount(previous, current, TERMINATE_1 * -1);
// the value should not decrease
int afterTerminate = checkPeakThreadCount(beforeTerminate, -1);

previous = current;
startThreads(DAEMON_THREADS_2);

// 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;
checkPeakThreadCount(-1, afterTerminate);

resetPeak(current);
// reset peak and ensure new threads increase the value
int beforeThreads3 = resetPeak();
startThreads(DAEMON_THREADS_3);

// terminate TERMINATE_3 number of threads and reset peak
current = terminateThreads(TERMINATE_1 + TERMINATE_2, TERMINATE_3);
checkPeakThreadCount(threads.size() + 1, -1); // + 1 for the current thread
checkPeakThreadCount(beforeThreads3, -1);

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);
return afterResetPeak;
}

if (afterResetPeak != current) {
throw new RuntimeException("Current Peak after reset = " +
afterResetPeak +
" Expected to be = current count = " + current);
}
private static void fail(String msg) {
ThreadDump.threadDump();
throw new RuntimeException(msg);
}

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 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 live[i] value is true

// 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);

1 comment on commit c82a673

@openjdk-notifier

This comment has been minimized.

Copy link

@openjdk-notifier openjdk-notifier bot commented on c82a673 Mar 18, 2021

Please sign in to comment.