1 /*
2  * Copyright (c) 2020, 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  * @summary Stress test that reaches the process limit for thread count, or time limit.
27  * @key stress
28  * @run main ThreadCountLimit
29  */
30 
31 import java.util.concurrent.CountDownLatch;
32 import java.util.ArrayList;
33 
34 public class ThreadCountLimit {
35 
36   static final int TIME_LIMIT_MS = 5000; // Create as many threads as possible in 5 sec
37 
38   static class Worker extends Thread {
39     private final int index;
40     private final CountDownLatch startSignal;
41 
Worker(int index, CountDownLatch startSignal)42     Worker(int index, CountDownLatch startSignal) {
43       this.index = index;
44       this.startSignal = startSignal;
45     }
46 
47     @Override
run()48     public void run() {
49       if ((index % 250) == 0) {
50         System.out.println("INFO: thread " + index + " waiting to start");
51       }
52 
53       try {
54         startSignal.await();
55       } 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");
69       }
70     }
71   }
72 
main(String[] args)73   public static void main(String[] args) {
74     CountDownLatch startSignal = new CountDownLatch(1);
75     ArrayList<Worker> workers = new ArrayList<Worker>();
76 
77     int count = 1;
78     long start = System.currentTimeMillis();
79     try {
80       while (true) {
81         Worker w = new Worker(count, startSignal);
82         w.start();
83         workers.add(w);
84         count++;
85 
86         long end = System.currentTimeMillis();
87         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");
90           break;
91         }
92       }
93     } catch (OutOfMemoryError e) {
94       if (e.getMessage().contains("unable to create native thread")) {
95         // Linux, macOS path
96         long end = System.currentTimeMillis();
97         System.out.println("INFO: reached this process thread count limit at " + count + " [" + (end - start) + " ms]");
98       } else {
99         throw e;
100       }
101     }
102 
103     startSignal.countDown();
104 
105     try {
106       for (Worker w : workers) {
107         w.join();
108       }
109     } catch (InterruptedException e) {
110       throw new Error("Unexpected: " + e);
111     }
112   }
113 }
114