11/*
2- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2525 * @test
2626 * @summary Stress test that reaches the process limit for thread count, or time limit.
2727 * @key stress
28- * @run main ThreadCountLimit
28+ * @run main/othervm -Xmx1g ThreadCountLimit
2929 */
3030
3131import java .util .concurrent .CountDownLatch ;
@@ -36,36 +36,18 @@ public class ThreadCountLimit {
3636 static final int TIME_LIMIT_MS = 5000 ; // Create as many threads as possible in 5 sec
3737
3838 static class Worker extends Thread {
39- private final int index ;
4039 private final CountDownLatch startSignal ;
4140
42- Worker (int index , CountDownLatch startSignal ) {
43- this .index = index ;
41+ Worker (CountDownLatch startSignal ) {
4442 this .startSignal = startSignal ;
4543 }
4644
4745 @ Override
4846 public void run () {
49- if ((index % 250 ) == 0 ) {
50- System .out .println ("INFO: thread " + index + " waiting to start" );
51- }
52-
5347 try {
5448 startSignal .await ();
5549 } catch (InterruptedException e ) {
56- throw new Error ("Unexpected: " + e );
57- }
58-
59- setName (String .valueOf (index ));
60-
61- Thread .yield ();
62-
63- if (index != Integer .parseInt (getName ())) {
64- throw new Error ("setName/getName failed!" );
65- }
66-
67- if ((index % 250 ) == 0 ) {
68- System .out .println ("INFO: thread " + getName () + " working" );
50+ throw new Error ("Unexpected" , e );
6951 }
7052 }
7153 }
@@ -74,27 +56,37 @@ public static void main(String[] args) {
7456 CountDownLatch startSignal = new CountDownLatch (1 );
7557 ArrayList <Worker > workers = new ArrayList <Worker >();
7658
59+ boolean reachedTimeLimit = false ;
60+ boolean reachedNativeOOM = false ;
61+ int countAtTimeLimit = -1 ;
62+ int countAtNativeOOM = -1 ;
63+
64+ // This is dangerous loop: it depletes system resources,
65+ // so doing additional things there that may end up allocating
66+ // Java/native memory risks failing the VM prematurely.
67+ // Avoid doing unnecessary calls, printouts, etc.
68+
7769 int count = 1 ;
7870 long start = System .currentTimeMillis ();
7971 try {
8072 while (true ) {
81- Worker w = new Worker (count , startSignal );
73+ Worker w = new Worker (startSignal );
8274 w .start ();
8375 workers .add (w );
8476 count ++;
8577
8678 long end = System .currentTimeMillis ();
8779 if ((end - start ) > TIME_LIMIT_MS ) {
88- // Windows path or a system with very large ulimit
89- System . out . println ( "INFO: reached the time limit " + TIME_LIMIT_MS + " ms, with " + count + " threads created" ) ;
80+ reachedTimeLimit = true ;
81+ countAtTimeLimit = count ;
9082 break ;
9183 }
9284 }
9385 } catch (OutOfMemoryError e ) {
9486 if (e .getMessage ().contains ("unable to create native thread" )) {
9587 // Linux, macOS path
96- long end = System . currentTimeMillis () ;
97- System . out . println ( "INFO: reached this process thread count limit at " + count + " [" + ( end - start ) + " ms]" ) ;
88+ reachedNativeOOM = true ;
89+ countAtNativeOOM = count ;
9890 } else {
9991 throw e ;
10092 }
@@ -107,7 +99,18 @@ public static void main(String[] args) {
10799 w .join ();
108100 }
109101 } catch (InterruptedException e ) {
110- throw new Error ("Unexpected: " + e );
102+ throw new Error ("Unexpected" , e );
103+ }
104+
105+ // Now that all threads have joined, we are away from dangerous
106+ // VM state and have enough memory to perform any other things.
107+ if (reachedTimeLimit ) {
108+ // Windows path or a system with very large ulimit
109+ System .out .println ("INFO: reached the time limit " + TIME_LIMIT_MS +
110+ " ms, with " + countAtTimeLimit + " threads created" );
111+ } else if (reachedNativeOOM ) {
112+ System .out .println ("INFO: reached this process thread count limit with " +
113+ countAtNativeOOM + " threads created" );
111114 }
112115 }
113116}
0 commit comments