1 /*
   2  * Copyright (c) 2007, 2010, 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 
  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 
  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 {
  63         public void checkPermission(Permission p) { /* bien sur, Monsieur */ }
  64     }
  65 
  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                        new Fun() {void f() {es.execute(nop);}});
  76             }
  77         } catch (Throwable t) { unexpected(t); }
  78     }
  79 
  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 
  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     private abstract static class Fun {abstract 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 }