OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / lib / classpath / external / jsr166 / java / util / concurrent / Executors.java
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 }