Deleted Added
sdiff udiff text old ( 15583:d6ccab83a5f8 ) new ( 16157:719a20f9075a )
full compact
1/*
2 * Copyright (c) 2007, 2015, 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 * @library /lib/testlibrary/
29 * @build jdk.testlibrary.RandomFactory
30 * @run main/othervm ConfigChanges
31 * @key randomness
32 * @author Martin Buchholz
33 */
34
35import static java.util.concurrent.TimeUnit.MILLISECONDS;
36import static java.util.concurrent.TimeUnit.MINUTES;
37import static java.util.concurrent.TimeUnit.NANOSECONDS;
38
39import java.security.Permission;
40import java.util.Random;
41import java.util.concurrent.ArrayBlockingQueue;
42import java.util.concurrent.CyclicBarrier;
43import java.util.concurrent.ExecutorService;
44import java.util.concurrent.RejectedExecutionException;
45import java.util.concurrent.ThreadFactory;
46import java.util.concurrent.ThreadPoolExecutor;
47import jdk.testlibrary.RandomFactory;
48
49public class ConfigChanges {
50 static final ThreadGroup tg = new ThreadGroup("pool");
51
52 static final Random rnd = RandomFactory.getRandom();
53
54 static void report(ThreadPoolExecutor tpe) {
55 try {
56 System.out.printf(
57 "active=%d submitted=%d completed=%d queued=%d sizes=%d/%d/%d%n",
58 tg.activeCount(),
59 tpe.getTaskCount(),
60 tpe.getCompletedTaskCount(),
61 tpe.getQueue().size(),
62 tpe.getPoolSize(),
63 tpe.getCorePoolSize(),
64 tpe.getMaximumPoolSize());
65 } catch (Throwable t) { unexpected(t); }
66 }
67
68 static void report(String label, ThreadPoolExecutor tpe) {
69 System.out.printf("%10s ", label);
70 report(tpe);
71 }
72
73 static class PermissiveSecurityManger extends SecurityManager {
74 public void checkPermission(Permission p) { /* bien sur, Monsieur */ }
75 }
76
77 static void checkShutdown(final ExecutorService es) {
78 final Runnable nop = new Runnable() {public void run() {}};
79 try {
80 if (new Random().nextBoolean()) {
81 check(es.isShutdown());
82 if (es instanceof ThreadPoolExecutor)
83 check(((ThreadPoolExecutor) es).isTerminating()
84 || es.isTerminated());
85 THROWS(RejectedExecutionException.class,
86 () -> es.execute(nop));
87 }
88 } catch (Throwable t) { unexpected(t); }
89 }
90
91 static void checkTerminated(final ThreadPoolExecutor tpe) {
92 try {
93 checkShutdown(tpe);
94 check(tpe.getQueue().isEmpty());
95 check(tpe.isTerminated());
96 check(! tpe.isTerminating());
97 equal(0, tpe.getActiveCount());
98 equal(0, tpe.getPoolSize());
99 equal(tpe.getTaskCount(), tpe.getCompletedTaskCount());
100 check(tpe.awaitTermination(0L, MINUTES));
101 } catch (Throwable t) { unexpected(t); }
102 }
103
104 static Runnable waiter(final CyclicBarrier barrier) {
105 return new Runnable() { public void run() {
106 try { barrier.await(); barrier.await(); }
107 catch (Throwable t) { unexpected(t); }}};
108 }
109
110 static volatile Runnable runnableDuJour;
111
112 static void awaitIdleness(ThreadPoolExecutor tpe, long taskCount) {
113 restart: for (;;) {
114 // check twice to make chance of race vanishingly small
115 for (int i = 0; i < 2; i++) {
116 if (tpe.getQueue().size() != 0 ||
117 tpe.getActiveCount() != 0 ||
118 tpe.getCompletedTaskCount() != taskCount) {
119 Thread.yield();
120 continue restart;
121 }
122 }
123 return;
124 }
125 }
126
127 private static void realMain(String[] args) throws Throwable {
128 if (rnd.nextBoolean())
129 System.setSecurityManager(new PermissiveSecurityManger());
130
131 final boolean prestart = rnd.nextBoolean();
132
133 final Thread.UncaughtExceptionHandler handler
134 = new Thread.UncaughtExceptionHandler() {
135 public void uncaughtException(Thread t, Throwable e) {
136 check(! Thread.currentThread().isInterrupted());
137 unexpected(e);
138 }};
139
140 final int n = 3;
141 final ThreadPoolExecutor tpe
142 = new ThreadPoolExecutor(n, 3*n,
143 3L, MINUTES,
144 new ArrayBlockingQueue<Runnable>(3*n));
145 tpe.setThreadFactory(new ThreadFactory() {
146 public Thread newThread(Runnable r) {
147 Thread t = new Thread(tg, r);
148 t.setUncaughtExceptionHandler(handler);
149 return t;
150 }});
151
152 if (prestart) {
153 tpe.prestartAllCoreThreads();
154 equal(n, tg.activeCount());
155 equal(n, tpe.getCorePoolSize());
156 equal(n, tpe.getLargestPoolSize());
157 }
158
159 final Runnable runRunnableDuJour =
160 new Runnable() { public void run() {
161 // Delay choice of action till last possible moment.
162 runnableDuJour.run(); }};
163 final CyclicBarrier pumpedUp = new CyclicBarrier(3*n + 1);
164 runnableDuJour = waiter(pumpedUp);
165
166 if (prestart) {
167 for (int i = 0; i < 1*n; i++)
168 tpe.execute(runRunnableDuJour);
169 // Wait for prestarted threads to dequeue their initial tasks.
170 while (! tpe.getQueue().isEmpty())
171 Thread.sleep(1);
172 for (int i = 0; i < 5*n; i++)
173 tpe.execute(runRunnableDuJour);
174 } else {
175 for (int i = 0; i < 6*n; i++)
176 tpe.execute(runRunnableDuJour);
177 }
178
179 //report("submitted", tpe);
180 pumpedUp.await();
181 equal(3*n, tg.activeCount());
182 equal(3*n, tpe.getMaximumPoolSize());
183 equal(3*n, tpe.getLargestPoolSize());
184 equal(n, tpe.getCorePoolSize());
185 equal(3*n, tpe.getActiveCount());
186 equal(6L*n, tpe.getTaskCount());
187 equal(0L, tpe.getCompletedTaskCount());
188
189 //report("pumped up", tpe);
190 tpe.setMaximumPoolSize(4*n);
191 equal(4*n, tpe.getMaximumPoolSize());
192 //report("pumped up2", tpe);
193 final CyclicBarrier pumpedUp2 = new CyclicBarrier(n + 1);
194 runnableDuJour = waiter(pumpedUp2);
195 for (int i = 0; i < 1*n; i++)
196 tpe.execute(runRunnableDuJour);
197 pumpedUp2.await();
198 equal(4*n, tg.activeCount());
199 equal(4*n, tpe.getMaximumPoolSize());
200 equal(4*n, tpe.getLargestPoolSize());
201 equal(4*n, tpe.getActiveCount());
202 equal(7L*n, tpe.getTaskCount());
203 equal(0L, tpe.getCompletedTaskCount());
204 //report("pumped up2", tpe);
205 runnableDuJour = new Runnable() { public void run() {}};
206
207 tpe.setMaximumPoolSize(2*n);
208 //report("after setMaximumPoolSize", tpe);
209
210 pumpedUp2.await();
211 pumpedUp.await();
212
213 while (tg.activeCount() != 2*n &&
214 tg.activeCount() != 2*n)
215 Thread.yield();
216 equal(2*n, tg.activeCount());
217 equal(2*n, tpe.getMaximumPoolSize());
218 equal(4*n, tpe.getLargestPoolSize());
219
220 //report("draining", tpe);
221 awaitIdleness(tpe, 7L*n);
222
223 equal(2*n, tg.activeCount());
224 equal(2*n, tpe.getMaximumPoolSize());
225 equal(4*n, tpe.getLargestPoolSize());
226
227 equal(7L*n, tpe.getTaskCount());
228 equal(7L*n, tpe.getCompletedTaskCount());
229 equal(0, tpe.getActiveCount());
230
231 equal(3L, tpe.getKeepAliveTime(MINUTES));
232 long t0 = System.nanoTime();
233 tpe.setKeepAliveTime(7L, MILLISECONDS);
234 equal(7L, tpe.getKeepAliveTime(MILLISECONDS));
235 while (tg.activeCount() > n &&
236 tg.activeCount() > n)
237 Thread.sleep(4);
238 equal(n, tg.activeCount());
239 check(System.nanoTime() - t0 >= tpe.getKeepAliveTime(NANOSECONDS));
240
241 //report("idle", tpe);
242 check(! tpe.allowsCoreThreadTimeOut());
243 t0 = System.nanoTime();
244 tpe.allowCoreThreadTimeOut(true);
245 check(tpe.allowsCoreThreadTimeOut());
246 while (tg.activeCount() > 0 &&
247 tg.activeCount() > 0)
248 Thread.sleep(4);
249 equal(tg.activeCount(), 0);
250
251 // The following assertion is almost always true, but may
252 // exceptionally not be during a transition from core count
253 // too high to allowCoreThreadTimeOut. Users will never
254 // notice, and we accept the small loss of testability.
255 //
256 // check(System.nanoTime() - t0 >= tpe.getKeepAliveTime(NANOSECONDS));
257
258 //report("idle", tpe);
259
260 tpe.shutdown();
261 checkShutdown(tpe);
262 check(tpe.awaitTermination(3L, MINUTES));
263 checkTerminated(tpe);
264 }
265
266 //--------------------- Infrastructure ---------------------------
267 static volatile int passed = 0, failed = 0;
268 static void pass() {passed++;}
269 static void fail() {failed++; Thread.dumpStack();}
270 static void fail(String msg) {System.out.println(msg); fail();}
271 static void unexpected(Throwable t) {failed++; t.printStackTrace();}
272 static void check(boolean cond) {if (cond) pass(); else fail();}
273 static void equal(Object x, Object y) {
274 if (x == null ? y == null : x.equals(y)) pass();
275 else fail(x + " not equal to " + y);}
276 public static void main(String[] args) throws Throwable {
277 try {realMain(args);} catch (Throwable t) {unexpected(t);}
278 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
279 if (failed > 0) throw new AssertionError("Some tests failed");}
280 interface Fun {void f() throws Throwable;}
281 static void THROWS(Class<? extends Throwable> k, Fun... fs) {
282 for (Fun f : fs)
283 try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
284 catch (Throwable t) {
285 if (k.isAssignableFrom(t.getClass())) pass();
286 else unexpected(t);}}
287}