1 /*
2  * Copyright (c) 2007, 2014, 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 6450200
27  * @summary Test proper handling of pool state changes
28  * @run main/othervm ConfigChanges
29  * @author Martin Buchholz
30  */
31 
32 import java.security.*;
33 import java.util.*;
34 import java.util.concurrent.*;
35 import java.util.concurrent.atomic.*;
36 import static java.util.concurrent.TimeUnit.*;
37 
38 public class ConfigChanges {
39     static final ThreadGroup tg = new ThreadGroup("pool");
40 
41     static final Random rnd = new Random();
42 
report(ThreadPoolExecutor tpe)43     static void report(ThreadPoolExecutor tpe) {
44         try {
45             System.out.printf(
46                 "active=%d submitted=%d completed=%d queued=%d sizes=%d/%d/%d%n",
47                 tg.activeCount(),
48                 tpe.getTaskCount(),
49                 tpe.getCompletedTaskCount(),
50                 tpe.getQueue().size(),
51                 tpe.getPoolSize(),
52                 tpe.getCorePoolSize(),
53                 tpe.getMaximumPoolSize());
54         } catch (Throwable t) { unexpected(t); }
55     }
56 
report(String label, ThreadPoolExecutor tpe)57     static void report(String label, ThreadPoolExecutor tpe) {
58         System.out.printf("%10s ", label);
59         report(tpe);
60     }
61 
62     static class PermissiveSecurityManger extends SecurityManager {
checkPermission(Permission p)63         public void checkPermission(Permission p) { /* bien sur, Monsieur */ }
64     }
65 
checkShutdown(final ExecutorService es)66     static void checkShutdown(final ExecutorService es) {
67         final Runnable nop = new Runnable() {public void run() {}};
68         try {
69             if (new Random().nextBoolean()) {
70                 check(es.isShutdown());
71                 if (es instanceof ThreadPoolExecutor)
72                     check(((ThreadPoolExecutor) es).isTerminating()
73                           || es.isTerminated());
74                 THROWS(RejectedExecutionException.class,
75                        () -> es.execute(nop));
76             }
77         } catch (Throwable t) { unexpected(t); }
78     }
79 
checkTerminated(final ThreadPoolExecutor tpe)80     static void checkTerminated(final ThreadPoolExecutor tpe) {
81         try {
82             checkShutdown(tpe);
83             check(tpe.getQueue().isEmpty());
84             check(tpe.isTerminated());
85             check(! tpe.isTerminating());
86             equal(tpe.getActiveCount(), 0);
87             equal(tpe.getPoolSize(), 0);
88             equal(tpe.getTaskCount(), tpe.getCompletedTaskCount());
89             check(tpe.awaitTermination(0, SECONDS));
90         } catch (Throwable t) { unexpected(t); }
91     }
92 
waiter(final CyclicBarrier barrier)93     static Runnable waiter(final CyclicBarrier barrier) {
94         return new Runnable() { public void run() {
95             try { barrier.await(); barrier.await(); }
96             catch (Throwable t) { unexpected(t); }}};
97     }
98 
99     static volatile Runnable runnableDuJour;
100 
101     private static void realMain(String[] args) throws Throwable {
102         if (rnd.nextBoolean())
103             System.setSecurityManager(new PermissiveSecurityManger());
104 
105         final boolean prestart = rnd.nextBoolean();
106 
107         final Thread.UncaughtExceptionHandler handler
108             = new Thread.UncaughtExceptionHandler() {
109                     public void uncaughtException(Thread t, Throwable e) {
110                         check(! Thread.currentThread().isInterrupted());
111                         unexpected(e);
112                     }};
113 
114         final int n = 3;
115         final ThreadPoolExecutor tpe
116             = new ThreadPoolExecutor(n, 3*n,
117                                      3L, MINUTES,
118                                      new ArrayBlockingQueue<Runnable>(3*n));
119         tpe.setThreadFactory(new ThreadFactory() {
120                 public Thread newThread(Runnable r) {
121                     Thread t = new Thread(tg, r);
122                     t.setUncaughtExceptionHandler(handler);
123                     return t;
124                 }});
125 
126         if (prestart) {
127             tpe.prestartAllCoreThreads();
128             equal(tg.activeCount(), n);
129             equal(tg.activeCount(), tpe.getCorePoolSize());
130         }
131 
132         final Runnable runRunnableDuJour =
133             new Runnable() { public void run() {
134                 // Delay choice of action till last possible moment.
135                 runnableDuJour.run(); }};
136         final CyclicBarrier pumpedUp = new CyclicBarrier(3*n + 1);
137         runnableDuJour = waiter(pumpedUp);
138 
139         if (prestart) {
140             for (int i = 0; i < 1*n; i++)
141                 tpe.execute(runRunnableDuJour);
142             // Wait for prestarted threads to dequeue their initial tasks.
143             while (! tpe.getQueue().isEmpty())
144                 Thread.sleep(10);
145             for (int i = 0; i < 5*n; i++)
146                 tpe.execute(runRunnableDuJour);
147         } else {
148             for (int i = 0; i < 6*n; i++)
149                 tpe.execute(runRunnableDuJour);
150         }
151 
152         //report("submitted", tpe);
153         pumpedUp.await();
154         equal(tg.activeCount(), 3*n);
155         equal(tg.activeCount(), tpe.getMaximumPoolSize());
156         equal(tpe.getCorePoolSize(), n);
157         //report("pumped up", tpe);
158         equal(tpe.getMaximumPoolSize(), 3*n);
159         tpe.setMaximumPoolSize(4*n);
160         equal(tpe.getMaximumPoolSize(), 4*n);
161         //report("pumped up2", tpe);
162         final CyclicBarrier pumpedUp2 = new CyclicBarrier(n + 1);
163         runnableDuJour = waiter(pumpedUp2);
164         for (int i = 0; i < 1*n; i++)
165             tpe.execute(runRunnableDuJour);
166         pumpedUp2.await();
167         equal(tg.activeCount(), 4*n);
168         equal(tg.activeCount(), tpe.getMaximumPoolSize());
169         equal(tpe.getCompletedTaskCount(), 0L);
170         //report("pumped up2", tpe);
171         runnableDuJour = new Runnable() { public void run() {}};
172 
173         tpe.setMaximumPoolSize(2*n);
174         //report("after set", tpe);
175 
176         pumpedUp2.await();
177         pumpedUp.await();
178 
179 //      while (tg.activeCount() != n &&
180 //             tg.activeCount() != n)
181 //          Thread.sleep(10);
182 //      equal(tg.activeCount(), n);
183 //      equal(tg.activeCount(), tpe.getCorePoolSize());
184 
185         while (tg.activeCount() != 2*n &&
186                tg.activeCount() != 2*n)
187             Thread.sleep(10);
188         equal(tg.activeCount(), 2*n);
189         equal(tg.activeCount(), tpe.getMaximumPoolSize());
190 
191 
192 //report("draining", tpe);
193         while (tpe.getCompletedTaskCount() < 7*n &&
194                tpe.getCompletedTaskCount() < 7*n)
195             Thread.sleep(10);
196 
197         //equal(tg.activeCount(), n);
198         //equal(tg.activeCount(), tpe.getCorePoolSize());
199         equal(tg.activeCount(), 2*n);
200         equal(tg.activeCount(), tpe.getMaximumPoolSize());
201 
202         equal(tpe.getTaskCount(), 7L*n);
203         equal(tpe.getCompletedTaskCount(), 7L*n);
204 
205         equal(tpe.getKeepAliveTime(MINUTES), 3L);
206         tpe.setKeepAliveTime(7L, MILLISECONDS);
207         equal(tpe.getKeepAliveTime(MILLISECONDS), 7L);
208         while (tg.activeCount() > n &&
209                tg.activeCount() > n)
210             Thread.sleep(10);
211         equal(tg.activeCount(), n);
212 
213         //report("idle", tpe);
214         check(! tpe.allowsCoreThreadTimeOut());
215         tpe.allowCoreThreadTimeOut(true);
216         check(tpe.allowsCoreThreadTimeOut());
217         while (tg.activeCount() > 0 &&
218                tg.activeCount() > 0)
219             Thread.sleep(10);
220         equal(tg.activeCount(), 0);
221 
222         //report("idle", tpe);
223 
224         tpe.shutdown();
225         checkShutdown(tpe);
226         check(tpe.awaitTermination(3L, MINUTES));
227         checkTerminated(tpe);
228     }
229 
230     //--------------------- Infrastructure ---------------------------
231     static volatile int passed = 0, failed = 0;
232     static void pass() {passed++;}
233     static void fail() {failed++; Thread.dumpStack();}
234     static void fail(String msg) {System.out.println(msg); fail();}
235     static void unexpected(Throwable t) {failed++; t.printStackTrace();}
236     static void check(boolean cond) {if (cond) pass(); else fail();}
237     static void equal(Object x, Object y) {
238         if (x == null ? y == null : x.equals(y)) pass();
239         else fail(x + " not equal to " + y);}
240     public static void main(String[] args) throws Throwable {
241         try {realMain(args);} catch (Throwable t) {unexpected(t);}
242         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
243         if (failed > 0) throw new AssertionError("Some tests failed");}
244     interface Fun {void f() throws Throwable;}
245     static void THROWS(Class<? extends Throwable> k, Fun... fs) {
246         for (Fun f : fs)
247             try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
248             catch (Throwable t) {
249                 if (k.isAssignableFrom(t.getClass())) pass();
250                 else unexpected(t);}}
251 }
252