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