Source for java.util.concurrent.Executors

   1: /*
   2:  * Written by Doug Lea with assistance from members of JCP JSR-166
   3:  * Expert Group and released to the public domain, as explained at
   4:  * http://creativecommons.org/licenses/publicdomain
   5:  */
   6: 
   7: package java.util.concurrent;
   8: import java.util.*;
   9: import java.util.concurrent.atomic.AtomicInteger;
  10: import java.security.AccessControlContext;
  11: import java.security.AccessController;
  12: import java.security.PrivilegedAction;
  13: import java.security.PrivilegedExceptionAction;
  14: import java.security.AccessControlException;
  15: 
  16: /**
  17:  * Factory and utility methods for {@link Executor}, {@link
  18:  * ExecutorService}, {@link ScheduledExecutorService}, {@link
  19:  * ThreadFactory}, and {@link Callable} classes defined in this
  20:  * package. This class supports the following kinds of methods:
  21:  *
  22:  * <ul>
  23:  *   <li> Methods that create and return an {@link ExecutorService}
  24:  *        set up with commonly useful configuration settings.
  25:  *   <li> Methods that create and return a {@link ScheduledExecutorService}
  26:  *        set up with commonly useful configuration settings.
  27:  *   <li> Methods that create and return a "wrapped" ExecutorService, that
  28:  *        disables reconfiguration by making implementation-specific methods
  29:  *        inaccessible.
  30:  *   <li> Methods that create and return a {@link ThreadFactory}
  31:  *        that sets newly created threads to a known state.
  32:  *   <li> Methods that create and return a {@link Callable}
  33:  *        out of other closure-like forms, so they can be used
  34:  *        in execution methods requiring <tt>Callable</tt>.
  35:  * </ul>
  36:  *
  37:  * @since 1.5
  38:  * @author Doug Lea
  39:  */
  40: public class Executors {
  41: 
  42:     /**
  43:      * Creates a thread pool that reuses a fixed number of threads
  44:      * operating off a shared unbounded queue.  At any point, at most
  45:      * <tt>nThreads</tt> threads will be active processing tasks.
  46:      * If additional tasks are submitted when all threads are active,
  47:      * they will wait in the queue until a thread is available.
  48:      * If any thread terminates due to a failure during execution
  49:      * prior to shutdown, a new one will take its place if needed to
  50:      * execute subsequent tasks.  The threads in the pool will exist
  51:      * until it is explicitly {@link ExecutorService#shutdown shutdown}.
  52:      *
  53:      * @param nThreads the number of threads in the pool
  54:      * @return the newly created thread pool
  55:      * @throws IllegalArgumentException if <tt>nThreads &lt;= 0</tt>
  56:      */
  57:     public static ExecutorService newFixedThreadPool(int nThreads) {
  58:         return new ThreadPoolExecutor(nThreads, nThreads,
  59:                                       0L, TimeUnit.MILLISECONDS,
  60:                                       new LinkedBlockingQueue<Runnable>());
  61:     }
  62: 
  63:     /**
  64:      * Creates a thread pool that reuses a fixed number of threads
  65:      * operating off a shared unbounded queue, using the provided
  66:      * ThreadFactory to create new threads when needed.  At any point,
  67:      * at most <tt>nThreads</tt> threads will be active processing
  68:      * tasks.  If additional tasks are submitted when all threads are
  69:      * active, they will wait in the queue until a thread is
  70:      * available.  If any thread terminates due to a failure during
  71:      * execution prior to shutdown, a new one will take its place if
  72:      * needed to execute subsequent tasks.  The threads in the pool will
  73:      * exist until it is explicitly {@link ExecutorService#shutdown
  74:      * shutdown}.
  75:      *
  76:      * @param nThreads the number of threads in the pool
  77:      * @param threadFactory the factory to use when creating new threads
  78:      * @return the newly created thread pool
  79:      * @throws NullPointerException if threadFactory is null
  80:      * @throws IllegalArgumentException if <tt>nThreads &lt;= 0</tt>
  81:      */
  82:     public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
  83:         return new ThreadPoolExecutor(nThreads, nThreads,
  84:                                       0L, TimeUnit.MILLISECONDS,
  85:                                       new LinkedBlockingQueue<Runnable>(),
  86:                                       threadFactory);
  87:     }
  88: 
  89:     /**
  90:      * Creates an Executor that uses a single worker thread operating
  91:      * off an unbounded queue. (Note however that if this single
  92:      * thread terminates due to a failure during execution prior to
  93:      * shutdown, a new one will take its place if needed to execute
  94:      * subsequent tasks.)  Tasks are guaranteed to execute
  95:      * sequentially, and no more than one task will be active at any
  96:      * given time. Unlike the otherwise equivalent
  97:      * <tt>newFixedThreadPool(1)</tt> the returned executor is
  98:      * guaranteed not to be reconfigurable to use additional threads.
  99:      *
 100:      * @return the newly created single-threaded Executor
 101:      */
 102:     public static ExecutorService newSingleThreadExecutor() {
 103:         return new FinalizableDelegatedExecutorService
 104:             (new ThreadPoolExecutor(1, 1,
 105:                                     0L, TimeUnit.MILLISECONDS,
 106:                                     new LinkedBlockingQueue<Runnable>()));
 107:     }
 108: 
 109:     /**
 110:      * Creates an Executor that uses a single worker thread operating
 111:      * off an unbounded queue, and uses the provided ThreadFactory to
 112:      * create a new thread when needed. Unlike the otherwise
 113:      * equivalent <tt>newFixedThreadPool(1, threadFactory)</tt> the
 114:      * returned executor is guaranteed not to be reconfigurable to use
 115:      * additional threads.
 116:      *
 117:      * @param threadFactory the factory to use when creating new
 118:      * threads
 119:      *
 120:      * @return the newly created single-threaded Executor
 121:      * @throws NullPointerException if threadFactory is null
 122:      */
 123:     public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
 124:         return new FinalizableDelegatedExecutorService
 125:             (new ThreadPoolExecutor(1, 1,
 126:                                     0L, TimeUnit.MILLISECONDS,
 127:                                     new LinkedBlockingQueue<Runnable>(),
 128:                                     threadFactory));
 129:     }
 130: 
 131:     /**
 132:      * Creates a thread pool that creates new threads as needed, but
 133:      * will reuse previously constructed threads when they are
 134:      * available.  These pools will typically improve the performance
 135:      * of programs that execute many short-lived asynchronous tasks.
 136:      * Calls to <tt>execute</tt> will reuse previously constructed
 137:      * threads if available. If no existing thread is available, a new
 138:      * thread will be created and added to the pool. Threads that have
 139:      * not been used for sixty seconds are terminated and removed from
 140:      * the cache. Thus, a pool that remains idle for long enough will
 141:      * not consume any resources. Note that pools with similar
 142:      * properties but different details (for example, timeout parameters)
 143:      * may be created using {@link ThreadPoolExecutor} constructors.
 144:      *
 145:      * @return the newly created thread pool
 146:      */
 147:     public static ExecutorService newCachedThreadPool() {
 148:         return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
 149:                                       60L, TimeUnit.SECONDS,
 150:                                       new SynchronousQueue<Runnable>());
 151:     }
 152: 
 153:     /**
 154:      * Creates a thread pool that creates new threads as needed, but
 155:      * will reuse previously constructed threads when they are
 156:      * available, and uses the provided
 157:      * ThreadFactory to create new threads when needed.
 158:      * @param threadFactory the factory to use when creating new threads
 159:      * @return the newly created thread pool
 160:      * @throws NullPointerException if threadFactory is null
 161:      */
 162:     public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
 163:         return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
 164:                                       60L, TimeUnit.SECONDS,
 165:                                       new SynchronousQueue<Runnable>(),
 166:                                       threadFactory);
 167:     }
 168: 
 169:     /**
 170:      * Creates a single-threaded executor that can schedule commands
 171:      * to run after a given delay, or to execute periodically.
 172:      * (Note however that if this single
 173:      * thread terminates due to a failure during execution prior to
 174:      * shutdown, a new one will take its place if needed to execute
 175:      * subsequent tasks.)  Tasks are guaranteed to execute
 176:      * sequentially, and no more than one task will be active at any
 177:      * given time. Unlike the otherwise equivalent
 178:      * <tt>newScheduledThreadPool(1)</tt> the returned executor is
 179:      * guaranteed not to be reconfigurable to use additional threads.
 180:      * @return the newly created scheduled executor
 181:      */
 182:     public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
 183:         return new DelegatedScheduledExecutorService
 184:             (new ScheduledThreadPoolExecutor(1));
 185:     }
 186: 
 187:     /**
 188:      * Creates a single-threaded executor that can schedule commands
 189:      * to run after a given delay, or to execute periodically.  (Note
 190:      * however that if this single thread terminates due to a failure
 191:      * during execution prior to shutdown, a new one will take its
 192:      * place if needed to execute subsequent tasks.)  Tasks are
 193:      * guaranteed to execute sequentially, and no more than one task
 194:      * will be active at any given time. Unlike the otherwise
 195:      * equivalent <tt>newScheduledThreadPool(1, threadFactory)</tt>
 196:      * the returned executor is guaranteed not to be reconfigurable to
 197:      * use additional threads.
 198:      * @param threadFactory the factory to use when creating new
 199:      * threads
 200:      * @return a newly created scheduled executor
 201:      * @throws NullPointerException if threadFactory is null
 202:      */
 203:     public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
 204:         return new DelegatedScheduledExecutorService
 205:             (new ScheduledThreadPoolExecutor(1, threadFactory));
 206:     }
 207: 
 208:     /**
 209:      * Creates a thread pool that can schedule commands to run after a
 210:      * given delay, or to execute periodically.
 211:      * @param corePoolSize the number of threads to keep in the pool,
 212:      * even if they are idle.
 213:      * @return a newly created scheduled thread pool
 214:      * @throws IllegalArgumentException if <tt>corePoolSize &lt; 0</tt>
 215:      */
 216:     public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
 217:         return new ScheduledThreadPoolExecutor(corePoolSize);
 218:     }
 219: 
 220:     /**
 221:      * Creates a thread pool that can schedule commands to run after a
 222:      * given delay, or to execute periodically.
 223:      * @param corePoolSize the number of threads to keep in the pool,
 224:      * even if they are idle.
 225:      * @param threadFactory the factory to use when the executor
 226:      * creates a new thread.
 227:      * @return a newly created scheduled thread pool
 228:      * @throws IllegalArgumentException if <tt>corePoolSize &lt; 0</tt>
 229:      * @throws NullPointerException if threadFactory is null
 230:      */
 231:     public static ScheduledExecutorService newScheduledThreadPool(
 232:             int corePoolSize, ThreadFactory threadFactory) {
 233:         return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
 234:     }
 235: 
 236: 
 237:     /**
 238:      * Returns an object that delegates all defined {@link
 239:      * ExecutorService} methods to the given executor, but not any
 240:      * other methods that might otherwise be accessible using
 241:      * casts. This provides a way to safely "freeze" configuration and
 242:      * disallow tuning of a given concrete implementation.
 243:      * @param executor the underlying implementation
 244:      * @return an <tt>ExecutorService</tt> instance
 245:      * @throws NullPointerException if executor null
 246:      */
 247:     public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
 248:         if (executor == null)
 249:             throw new NullPointerException();
 250:         return new DelegatedExecutorService(executor);
 251:     }
 252: 
 253:     /**
 254:      * Returns an object that delegates all defined {@link
 255:      * ScheduledExecutorService} methods to the given executor, but
 256:      * not any other methods that might otherwise be accessible using
 257:      * casts. This provides a way to safely "freeze" configuration and
 258:      * disallow tuning of a given concrete implementation.
 259:      * @param executor the underlying implementation
 260:      * @return a <tt>ScheduledExecutorService</tt> instance
 261:      * @throws NullPointerException if executor null
 262:      */
 263:     public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
 264:         if (executor == null)
 265:             throw new NullPointerException();
 266:         return new DelegatedScheduledExecutorService(executor);
 267:     }
 268: 
 269:     /**
 270:      * Returns a default thread factory used to create new threads.
 271:      * This factory creates all new threads used by an Executor in the
 272:      * same {@link ThreadGroup}. If there is a {@link
 273:      * java.lang.SecurityManager}, it uses the group of {@link
 274:      * System#getSecurityManager}, else the group of the thread
 275:      * invoking this <tt>defaultThreadFactory</tt> method. Each new
 276:      * thread is created as a non-daemon thread with priority set to
 277:      * the smaller of <tt>Thread.NORM_PRIORITY</tt> and the maximum
 278:      * priority permitted in the thread group.  New threads have names
 279:      * accessible via {@link Thread#getName} of
 280:      * <em>pool-N-thread-M</em>, where <em>N</em> is the sequence
 281:      * number of this factory, and <em>M</em> is the sequence number
 282:      * of the thread created by this factory.
 283:      * @return a thread factory
 284:      */
 285:     public static ThreadFactory defaultThreadFactory() {
 286:         return new DefaultThreadFactory();
 287:     }
 288: 
 289:     /**
 290:      * Returns a thread factory used to create new threads that
 291:      * have the same permissions as the current thread.
 292:      * This factory creates threads with the same settings as {@link
 293:      * Executors#defaultThreadFactory}, additionally setting the
 294:      * AccessControlContext and contextClassLoader of new threads to
 295:      * be the same as the thread invoking this
 296:      * <tt>privilegedThreadFactory</tt> method.  A new
 297:      * <tt>privilegedThreadFactory</tt> can be created within an
 298:      * {@link AccessController#doPrivileged} action setting the
 299:      * current thread's access control context to create threads with
 300:      * the selected permission settings holding within that action.
 301:      *
 302:      * <p> Note that while tasks running within such threads will have
 303:      * the same access control and class loader settings as the
 304:      * current thread, they need not have the same {@link
 305:      * java.lang.ThreadLocal} or {@link
 306:      * java.lang.InheritableThreadLocal} values. If necessary,
 307:      * particular values of thread locals can be set or reset before
 308:      * any task runs in {@link ThreadPoolExecutor} subclasses using
 309:      * {@link ThreadPoolExecutor#beforeExecute}. Also, if it is
 310:      * necessary to initialize worker threads to have the same
 311:      * InheritableThreadLocal settings as some other designated
 312:      * thread, you can create a custom ThreadFactory in which that
 313:      * thread waits for and services requests to create others that
 314:      * will inherit its values.
 315:      *
 316:      * @return a thread factory
 317:      * @throws AccessControlException if the current access control
 318:      * context does not have permission to both get and set context
 319:      * class loader.
 320:      */
 321:     public static ThreadFactory privilegedThreadFactory() {
 322:         return new PrivilegedThreadFactory();
 323:     }
 324: 
 325:     /**
 326:      * Returns a {@link Callable} object that, when
 327:      * called, runs the given task and returns the given result.  This
 328:      * can be useful when applying methods requiring a
 329:      * <tt>Callable</tt> to an otherwise resultless action.
 330:      * @param task the task to run
 331:      * @param result the result to return
 332:      * @return a callable object
 333:      * @throws NullPointerException if task null
 334:      */
 335:     public static <T> Callable<T> callable(Runnable task, T result) {
 336:         if (task == null)
 337:             throw new NullPointerException();
 338:         return new RunnableAdapter<T>(task, result);
 339:     }
 340: 
 341:     /**
 342:      * Returns a {@link Callable} object that, when
 343:      * called, runs the given task and returns <tt>null</tt>.
 344:      * @param task the task to run
 345:      * @return a callable object
 346:      * @throws NullPointerException if task null
 347:      */
 348:     public static Callable<Object> callable(Runnable task) {
 349:         if (task == null)
 350:             throw new NullPointerException();
 351:         return new RunnableAdapter<Object>(task, null);
 352:     }
 353: 
 354:     /**
 355:      * Returns a {@link Callable} object that, when
 356:      * called, runs the given privileged action and returns its result.
 357:      * @param action the privileged action to run
 358:      * @return a callable object
 359:      * @throws NullPointerException if action null
 360:      */
 361:     public static Callable<Object> callable(final PrivilegedAction<?> action) {
 362:         if (action == null)
 363:             throw new NullPointerException();
 364:         return new Callable<Object>() {
 365:         public Object call() { return action.run(); }};
 366:     }
 367: 
 368:     /**
 369:      * Returns a {@link Callable} object that, when
 370:      * called, runs the given privileged exception action and returns
 371:      * its result.
 372:      * @param action the privileged exception action to run
 373:      * @return a callable object
 374:      * @throws NullPointerException if action null
 375:      */
 376:     public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) {
 377:         if (action == null)
 378:             throw new NullPointerException();
 379:     return new Callable<Object>() {
 380:         public Object call() throws Exception { return action.run(); }};
 381:     }
 382: 
 383:     /**
 384:      * Returns a {@link Callable} object that will, when
 385:      * called, execute the given <tt>callable</tt> under the current
 386:      * access control context. This method should normally be
 387:      * invoked within an {@link AccessController#doPrivileged} action
 388:      * to create callables that will, if possible, execute under the
 389:      * selected permission settings holding within that action; or if
 390:      * not possible, throw an associated {@link
 391:      * AccessControlException}.
 392:      * @param callable the underlying task
 393:      * @return a callable object
 394:      * @throws NullPointerException if callable null
 395:      *
 396:      */
 397:     public static <T> Callable<T> privilegedCallable(Callable<T> callable) {
 398:         if (callable == null)
 399:             throw new NullPointerException();
 400:         return new PrivilegedCallable<T>(callable);
 401:     }
 402: 
 403:     /**
 404:      * Returns a {@link Callable} object that will, when
 405:      * called, execute the given <tt>callable</tt> under the current
 406:      * access control context, with the current context class loader
 407:      * as the context class loader. This method should normally be
 408:      * invoked within an {@link AccessController#doPrivileged} action
 409:      * to create callables that will, if possible, execute under the
 410:      * selected permission settings holding within that action; or if
 411:      * not possible, throw an associated {@link
 412:      * AccessControlException}.
 413:      * @param callable the underlying task
 414:      *
 415:      * @return a callable object
 416:      * @throws NullPointerException if callable null
 417:      * @throws AccessControlException if the current access control
 418:      * context does not have permission to both set and get context
 419:      * class loader.
 420:      */
 421:     public static <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable) {
 422:         if (callable == null)
 423:             throw new NullPointerException();
 424:         return new PrivilegedCallableUsingCurrentClassLoader<T>(callable);
 425:     }
 426: 
 427:     // Non-public classes supporting the public methods
 428: 
 429:     /**
 430:      * A callable that runs given task and returns given result
 431:      */
 432:     static final class RunnableAdapter<T> implements Callable<T> {
 433:         final Runnable task;
 434:         final T result;
 435:         RunnableAdapter(Runnable  task, T result) {
 436:             this.task = task;
 437:             this.result = result;
 438:         }
 439:         public T call() {
 440:             task.run();
 441:             return result;
 442:         }
 443:     }
 444: 
 445:     /**
 446:      * A callable that runs under established access control settings
 447:      */
 448:     static final class PrivilegedCallable<T> implements Callable<T> {
 449:         private final AccessControlContext acc;
 450:         private final Callable<T> task;
 451:         private T result;
 452:         private Exception exception;
 453:         PrivilegedCallable(Callable<T> task) {
 454:             this.task = task;
 455:             this.acc = AccessController.getContext();
 456:         }
 457: 
 458:         public T call() throws Exception {
 459:             AccessController.doPrivileged(new PrivilegedAction<T>() {
 460:                     public T run() {
 461:                         try {
 462:                             result = task.call();
 463:                         } catch (Exception ex) {
 464:                             exception = ex;
 465:                         }
 466:                         return null;
 467:                     }
 468:                 }, acc);
 469:             if (exception != null)
 470:                 throw exception;
 471:             else
 472:                 return result;
 473:         }
 474:     }
 475: 
 476:     /**
 477:      * A callable that runs under established access control settings and
 478:      * current ClassLoader
 479:      */
 480:     static final class PrivilegedCallableUsingCurrentClassLoader<T> implements Callable<T> {
 481:         private final ClassLoader ccl;
 482:         private final AccessControlContext acc;
 483:         private final Callable<T> task;
 484:         private T result;
 485:         private Exception exception;
 486:         PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {
 487:             this.task = task;
 488:             this.ccl = Thread.currentThread().getContextClassLoader();
 489:             this.acc = AccessController.getContext();
 490:             acc.checkPermission(new RuntimePermission("getContextClassLoader"));
 491:             acc.checkPermission(new RuntimePermission("setContextClassLoader"));
 492:         }
 493: 
 494:         public T call() throws Exception {
 495:             AccessController.doPrivileged(new PrivilegedAction<T>() {
 496:                     public T run() {
 497:                         ClassLoader savedcl = null;
 498:                         Thread t = Thread.currentThread();
 499:                         try {
 500:                             ClassLoader cl = t.getContextClassLoader();
 501:                             if (ccl != cl) {
 502:                                 t.setContextClassLoader(ccl);
 503:                                 savedcl = cl;
 504:                             }
 505:                             result = task.call();
 506:                         } catch (Exception ex) {
 507:                             exception = ex;
 508:                         } finally {
 509:                             if (savedcl != null)
 510:                                 t.setContextClassLoader(savedcl);
 511:                         }
 512:                         return null;
 513:                     }
 514:                 }, acc);
 515:             if (exception != null)
 516:                 throw exception;
 517:             else
 518:                 return result;
 519:         }
 520:     }
 521: 
 522:     /**
 523:      * The default thread factory
 524:      */
 525:     static class DefaultThreadFactory implements ThreadFactory {
 526:         static final AtomicInteger poolNumber = new AtomicInteger(1);
 527:         final ThreadGroup group;
 528:         final AtomicInteger threadNumber = new AtomicInteger(1);
 529:         final String namePrefix;
 530: 
 531:         DefaultThreadFactory() {
 532:             SecurityManager s = System.getSecurityManager();
 533:             group = (s != null)? s.getThreadGroup() :
 534:                                  Thread.currentThread().getThreadGroup();
 535:             namePrefix = "pool-" +
 536:                           poolNumber.getAndIncrement() +
 537:                          "-thread-";
 538:         }
 539: 
 540:         public Thread newThread(Runnable r) {
 541:             Thread t = new Thread(group, r,
 542:                                   namePrefix + threadNumber.getAndIncrement(),
 543:                                   0);
 544:             if (t.isDaemon())
 545:                 t.setDaemon(false);
 546:             if (t.getPriority() != Thread.NORM_PRIORITY)
 547:                 t.setPriority(Thread.NORM_PRIORITY);
 548:             return t;
 549:         }
 550:     }
 551: 
 552:     /**
 553:      *  Thread factory capturing access control and class loader
 554:      */
 555:     static class PrivilegedThreadFactory extends DefaultThreadFactory {
 556:         private final ClassLoader ccl;
 557:         private final AccessControlContext acc;
 558: 
 559:         PrivilegedThreadFactory() {
 560:             super();
 561:             this.ccl = Thread.currentThread().getContextClassLoader();
 562:             this.acc = AccessController.getContext();
 563:             acc.checkPermission(new RuntimePermission("setContextClassLoader"));
 564:         }
 565: 
 566:         public Thread newThread(final Runnable r) {
 567:             return super.newThread(new Runnable() {
 568:                 public void run() {
 569:                     AccessController.doPrivileged(new PrivilegedAction<Object>() {
 570:                         public Object run() {
 571:                             Thread.currentThread().setContextClassLoader(ccl);
 572:                             r.run();
 573:                             return null;
 574:                         }
 575:                     }, acc);
 576:                 }
 577:             });
 578:         }
 579: 
 580:     }
 581: 
 582:     /**
 583:      * A wrapper class that exposes only the ExecutorService methods
 584:      * of an ExecutorService implementation.
 585:      */
 586:     static class DelegatedExecutorService extends AbstractExecutorService {
 587:         private final ExecutorService e;
 588:         DelegatedExecutorService(ExecutorService executor) { e = executor; }
 589:         public void execute(Runnable command) { e.execute(command); }
 590:         public void shutdown() { e.shutdown(); }
 591:         public List<Runnable> shutdownNow() { return e.shutdownNow(); }
 592:         public boolean isShutdown() { return e.isShutdown(); }
 593:         public boolean isTerminated() { return e.isTerminated(); }
 594:         public boolean awaitTermination(long timeout, TimeUnit unit)
 595:             throws InterruptedException {
 596:             return e.awaitTermination(timeout, unit);
 597:         }
 598:         public Future<?> submit(Runnable task) {
 599:             return e.submit(task);
 600:         }
 601:         public <T> Future<T> submit(Callable<T> task) {
 602:             return e.submit(task);
 603:         }
 604:         public <T> Future<T> submit(Runnable task, T result) {
 605:             return e.submit(task, result);
 606:         }
 607:         public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
 608:             throws InterruptedException {
 609:             return e.invokeAll(tasks);
 610:         }
 611:         public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
 612:                                              long timeout, TimeUnit unit)
 613:             throws InterruptedException {
 614:             return e.invokeAll(tasks, timeout, unit);
 615:         }
 616:         public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
 617:             throws InterruptedException, ExecutionException {
 618:             return e.invokeAny(tasks);
 619:         }
 620:         public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
 621:                                long timeout, TimeUnit unit)
 622:             throws InterruptedException, ExecutionException, TimeoutException {
 623:             return e.invokeAny(tasks, timeout, unit);
 624:         }
 625:     }
 626: 
 627:     static class FinalizableDelegatedExecutorService
 628:     extends DelegatedExecutorService {
 629:     FinalizableDelegatedExecutorService(ExecutorService executor) {
 630:         super(executor);
 631:     }
 632:     protected void finalize()  {
 633:         super.shutdown();
 634:     }
 635:     }
 636: 
 637:     /**
 638:      * A wrapper class that exposes only the ScheduledExecutorService
 639:      * methods of a ScheduledExecutorService implementation.
 640:      */
 641:     static class DelegatedScheduledExecutorService
 642:             extends DelegatedExecutorService
 643:             implements ScheduledExecutorService {
 644:         private final ScheduledExecutorService e;
 645:         DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
 646:             super(executor);
 647:             e = executor;
 648:         }
 649:         public ScheduledFuture<?> schedule(Runnable command, long delay,  TimeUnit unit) {
 650:             return e.schedule(command, delay, unit);
 651:         }
 652:         public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
 653:             return e.schedule(callable, delay, unit);
 654:         }
 655:         public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay,  long period, TimeUnit unit) {
 656:             return e.scheduleAtFixedRate(command, initialDelay, period, unit);
 657:         }
 658:         public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,  long delay, TimeUnit unit) {
 659:             return e.scheduleWithFixedDelay(command, initialDelay, delay, unit);
 660:         }
 661:     }
 662: 
 663: 
 664:     /** Cannot instantiate. */
 665:     private Executors() {}
 666: }