rt/emul/compact/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 19 Mar 2016 10:46:31 +0100
branchjdk7-b147
changeset 1890 212417b74b72
permissions -rw-r--r--
Bringing in all concurrent package from JDK7-b147
jaroslav@1890
     1
/*
jaroslav@1890
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@1890
     3
 *
jaroslav@1890
     4
 * This code is free software; you can redistribute it and/or modify it
jaroslav@1890
     5
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@1890
     6
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@1890
     7
 * particular file as subject to the "Classpath" exception as provided
jaroslav@1890
     8
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@1890
     9
 *
jaroslav@1890
    10
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@1890
    11
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@1890
    12
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@1890
    13
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@1890
    14
 * accompanied this code).
jaroslav@1890
    15
 *
jaroslav@1890
    16
 * You should have received a copy of the GNU General Public License version
jaroslav@1890
    17
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@1890
    18
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@1890
    19
 *
jaroslav@1890
    20
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@1890
    21
 * or visit www.oracle.com if you need additional information or have any
jaroslav@1890
    22
 * questions.
jaroslav@1890
    23
 */
jaroslav@1890
    24
jaroslav@1890
    25
/*
jaroslav@1890
    26
 * This file is available under and governed by the GNU General Public
jaroslav@1890
    27
 * License version 2 only, as published by the Free Software Foundation.
jaroslav@1890
    28
 * However, the following notice accompanied the original version of this
jaroslav@1890
    29
 * file:
jaroslav@1890
    30
 *
jaroslav@1890
    31
 * Written by Doug Lea with assistance from members of JCP JSR-166
jaroslav@1890
    32
 * Expert Group and released to the public domain, as explained at
jaroslav@1890
    33
 * http://creativecommons.org/publicdomain/zero/1.0/
jaroslav@1890
    34
 */
jaroslav@1890
    35
jaroslav@1890
    36
package java.util.concurrent;
jaroslav@1890
    37
import java.util.concurrent.atomic.*;
jaroslav@1890
    38
import java.util.concurrent.locks.*;
jaroslav@1890
    39
import java.util.*;
jaroslav@1890
    40
jaroslav@1890
    41
/**
jaroslav@1890
    42
 * A {@link ThreadPoolExecutor} that can additionally schedule
jaroslav@1890
    43
 * commands to run after a given delay, or to execute
jaroslav@1890
    44
 * periodically. This class is preferable to {@link java.util.Timer}
jaroslav@1890
    45
 * when multiple worker threads are needed, or when the additional
jaroslav@1890
    46
 * flexibility or capabilities of {@link ThreadPoolExecutor} (which
jaroslav@1890
    47
 * this class extends) are required.
jaroslav@1890
    48
 *
jaroslav@1890
    49
 * <p>Delayed tasks execute no sooner than they are enabled, but
jaroslav@1890
    50
 * without any real-time guarantees about when, after they are
jaroslav@1890
    51
 * enabled, they will commence. Tasks scheduled for exactly the same
jaroslav@1890
    52
 * execution time are enabled in first-in-first-out (FIFO) order of
jaroslav@1890
    53
 * submission.
jaroslav@1890
    54
 *
jaroslav@1890
    55
 * <p>When a submitted task is cancelled before it is run, execution
jaroslav@1890
    56
 * is suppressed. By default, such a cancelled task is not
jaroslav@1890
    57
 * automatically removed from the work queue until its delay
jaroslav@1890
    58
 * elapses. While this enables further inspection and monitoring, it
jaroslav@1890
    59
 * may also cause unbounded retention of cancelled tasks. To avoid
jaroslav@1890
    60
 * this, set {@link #setRemoveOnCancelPolicy} to {@code true}, which
jaroslav@1890
    61
 * causes tasks to be immediately removed from the work queue at
jaroslav@1890
    62
 * time of cancellation.
jaroslav@1890
    63
 *
jaroslav@1890
    64
 * <p>Successive executions of a task scheduled via
jaroslav@1890
    65
 * {@code scheduleAtFixedRate} or
jaroslav@1890
    66
 * {@code scheduleWithFixedDelay} do not overlap. While different
jaroslav@1890
    67
 * executions may be performed by different threads, the effects of
jaroslav@1890
    68
 * prior executions <a
jaroslav@1890
    69
 * href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
jaroslav@1890
    70
 * those of subsequent ones.
jaroslav@1890
    71
 *
jaroslav@1890
    72
 * <p>While this class inherits from {@link ThreadPoolExecutor}, a few
jaroslav@1890
    73
 * of the inherited tuning methods are not useful for it. In
jaroslav@1890
    74
 * particular, because it acts as a fixed-sized pool using
jaroslav@1890
    75
 * {@code corePoolSize} threads and an unbounded queue, adjustments
jaroslav@1890
    76
 * to {@code maximumPoolSize} have no useful effect. Additionally, it
jaroslav@1890
    77
 * is almost never a good idea to set {@code corePoolSize} to zero or
jaroslav@1890
    78
 * use {@code allowCoreThreadTimeOut} because this may leave the pool
jaroslav@1890
    79
 * without threads to handle tasks once they become eligible to run.
jaroslav@1890
    80
 *
jaroslav@1890
    81
 * <p><b>Extension notes:</b> This class overrides the
jaroslav@1890
    82
 * {@link ThreadPoolExecutor#execute execute} and
jaroslav@1890
    83
 * {@link AbstractExecutorService#submit(Runnable) submit}
jaroslav@1890
    84
 * methods to generate internal {@link ScheduledFuture} objects to
jaroslav@1890
    85
 * control per-task delays and scheduling.  To preserve
jaroslav@1890
    86
 * functionality, any further overrides of these methods in
jaroslav@1890
    87
 * subclasses must invoke superclass versions, which effectively
jaroslav@1890
    88
 * disables additional task customization.  However, this class
jaroslav@1890
    89
 * provides alternative protected extension method
jaroslav@1890
    90
 * {@code decorateTask} (one version each for {@code Runnable} and
jaroslav@1890
    91
 * {@code Callable}) that can be used to customize the concrete task
jaroslav@1890
    92
 * types used to execute commands entered via {@code execute},
jaroslav@1890
    93
 * {@code submit}, {@code schedule}, {@code scheduleAtFixedRate},
jaroslav@1890
    94
 * and {@code scheduleWithFixedDelay}.  By default, a
jaroslav@1890
    95
 * {@code ScheduledThreadPoolExecutor} uses a task type extending
jaroslav@1890
    96
 * {@link FutureTask}. However, this may be modified or replaced using
jaroslav@1890
    97
 * subclasses of the form:
jaroslav@1890
    98
 *
jaroslav@1890
    99
 *  <pre> {@code
jaroslav@1890
   100
 * public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
jaroslav@1890
   101
 *
jaroslav@1890
   102
 *   static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
jaroslav@1890
   103
 *
jaroslav@1890
   104
 *   protected <V> RunnableScheduledFuture<V> decorateTask(
jaroslav@1890
   105
 *                Runnable r, RunnableScheduledFuture<V> task) {
jaroslav@1890
   106
 *       return new CustomTask<V>(r, task);
jaroslav@1890
   107
 *   }
jaroslav@1890
   108
 *
jaroslav@1890
   109
 *   protected <V> RunnableScheduledFuture<V> decorateTask(
jaroslav@1890
   110
 *                Callable<V> c, RunnableScheduledFuture<V> task) {
jaroslav@1890
   111
 *       return new CustomTask<V>(c, task);
jaroslav@1890
   112
 *   }
jaroslav@1890
   113
 *   // ... add constructors, etc.
jaroslav@1890
   114
 * }}</pre>
jaroslav@1890
   115
 *
jaroslav@1890
   116
 * @since 1.5
jaroslav@1890
   117
 * @author Doug Lea
jaroslav@1890
   118
 */
jaroslav@1890
   119
public class ScheduledThreadPoolExecutor
jaroslav@1890
   120
        extends ThreadPoolExecutor
jaroslav@1890
   121
        implements ScheduledExecutorService {
jaroslav@1890
   122
jaroslav@1890
   123
    /*
jaroslav@1890
   124
     * This class specializes ThreadPoolExecutor implementation by
jaroslav@1890
   125
     *
jaroslav@1890
   126
     * 1. Using a custom task type, ScheduledFutureTask for
jaroslav@1890
   127
     *    tasks, even those that don't require scheduling (i.e.,
jaroslav@1890
   128
     *    those submitted using ExecutorService execute, not
jaroslav@1890
   129
     *    ScheduledExecutorService methods) which are treated as
jaroslav@1890
   130
     *    delayed tasks with a delay of zero.
jaroslav@1890
   131
     *
jaroslav@1890
   132
     * 2. Using a custom queue (DelayedWorkQueue), a variant of
jaroslav@1890
   133
     *    unbounded DelayQueue. The lack of capacity constraint and
jaroslav@1890
   134
     *    the fact that corePoolSize and maximumPoolSize are
jaroslav@1890
   135
     *    effectively identical simplifies some execution mechanics
jaroslav@1890
   136
     *    (see delayedExecute) compared to ThreadPoolExecutor.
jaroslav@1890
   137
     *
jaroslav@1890
   138
     * 3. Supporting optional run-after-shutdown parameters, which
jaroslav@1890
   139
     *    leads to overrides of shutdown methods to remove and cancel
jaroslav@1890
   140
     *    tasks that should NOT be run after shutdown, as well as
jaroslav@1890
   141
     *    different recheck logic when task (re)submission overlaps
jaroslav@1890
   142
     *    with a shutdown.
jaroslav@1890
   143
     *
jaroslav@1890
   144
     * 4. Task decoration methods to allow interception and
jaroslav@1890
   145
     *    instrumentation, which are needed because subclasses cannot
jaroslav@1890
   146
     *    otherwise override submit methods to get this effect. These
jaroslav@1890
   147
     *    don't have any impact on pool control logic though.
jaroslav@1890
   148
     */
jaroslav@1890
   149
jaroslav@1890
   150
    /**
jaroslav@1890
   151
     * False if should cancel/suppress periodic tasks on shutdown.
jaroslav@1890
   152
     */
jaroslav@1890
   153
    private volatile boolean continueExistingPeriodicTasksAfterShutdown;
jaroslav@1890
   154
jaroslav@1890
   155
    /**
jaroslav@1890
   156
     * False if should cancel non-periodic tasks on shutdown.
jaroslav@1890
   157
     */
jaroslav@1890
   158
    private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
jaroslav@1890
   159
jaroslav@1890
   160
    /**
jaroslav@1890
   161
     * True if ScheduledFutureTask.cancel should remove from queue
jaroslav@1890
   162
     */
jaroslav@1890
   163
    private volatile boolean removeOnCancel = false;
jaroslav@1890
   164
jaroslav@1890
   165
    /**
jaroslav@1890
   166
     * Sequence number to break scheduling ties, and in turn to
jaroslav@1890
   167
     * guarantee FIFO order among tied entries.
jaroslav@1890
   168
     */
jaroslav@1890
   169
    private static final AtomicLong sequencer = new AtomicLong(0);
jaroslav@1890
   170
jaroslav@1890
   171
    /**
jaroslav@1890
   172
     * Returns current nanosecond time.
jaroslav@1890
   173
     */
jaroslav@1890
   174
    final long now() {
jaroslav@1890
   175
        return System.nanoTime();
jaroslav@1890
   176
    }
jaroslav@1890
   177
jaroslav@1890
   178
    private class ScheduledFutureTask<V>
jaroslav@1890
   179
            extends FutureTask<V> implements RunnableScheduledFuture<V> {
jaroslav@1890
   180
jaroslav@1890
   181
        /** Sequence number to break ties FIFO */
jaroslav@1890
   182
        private final long sequenceNumber;
jaroslav@1890
   183
jaroslav@1890
   184
        /** The time the task is enabled to execute in nanoTime units */
jaroslav@1890
   185
        private long time;
jaroslav@1890
   186
jaroslav@1890
   187
        /**
jaroslav@1890
   188
         * Period in nanoseconds for repeating tasks.  A positive
jaroslav@1890
   189
         * value indicates fixed-rate execution.  A negative value
jaroslav@1890
   190
         * indicates fixed-delay execution.  A value of 0 indicates a
jaroslav@1890
   191
         * non-repeating task.
jaroslav@1890
   192
         */
jaroslav@1890
   193
        private final long period;
jaroslav@1890
   194
jaroslav@1890
   195
        /** The actual task to be re-enqueued by reExecutePeriodic */
jaroslav@1890
   196
        RunnableScheduledFuture<V> outerTask = this;
jaroslav@1890
   197
jaroslav@1890
   198
        /**
jaroslav@1890
   199
         * Index into delay queue, to support faster cancellation.
jaroslav@1890
   200
         */
jaroslav@1890
   201
        int heapIndex;
jaroslav@1890
   202
jaroslav@1890
   203
        /**
jaroslav@1890
   204
         * Creates a one-shot action with given nanoTime-based trigger time.
jaroslav@1890
   205
         */
jaroslav@1890
   206
        ScheduledFutureTask(Runnable r, V result, long ns) {
jaroslav@1890
   207
            super(r, result);
jaroslav@1890
   208
            this.time = ns;
jaroslav@1890
   209
            this.period = 0;
jaroslav@1890
   210
            this.sequenceNumber = sequencer.getAndIncrement();
jaroslav@1890
   211
        }
jaroslav@1890
   212
jaroslav@1890
   213
        /**
jaroslav@1890
   214
         * Creates a periodic action with given nano time and period.
jaroslav@1890
   215
         */
jaroslav@1890
   216
        ScheduledFutureTask(Runnable r, V result, long ns, long period) {
jaroslav@1890
   217
            super(r, result);
jaroslav@1890
   218
            this.time = ns;
jaroslav@1890
   219
            this.period = period;
jaroslav@1890
   220
            this.sequenceNumber = sequencer.getAndIncrement();
jaroslav@1890
   221
        }
jaroslav@1890
   222
jaroslav@1890
   223
        /**
jaroslav@1890
   224
         * Creates a one-shot action with given nanoTime-based trigger.
jaroslav@1890
   225
         */
jaroslav@1890
   226
        ScheduledFutureTask(Callable<V> callable, long ns) {
jaroslav@1890
   227
            super(callable);
jaroslav@1890
   228
            this.time = ns;
jaroslav@1890
   229
            this.period = 0;
jaroslav@1890
   230
            this.sequenceNumber = sequencer.getAndIncrement();
jaroslav@1890
   231
        }
jaroslav@1890
   232
jaroslav@1890
   233
        public long getDelay(TimeUnit unit) {
jaroslav@1890
   234
            return unit.convert(time - now(), TimeUnit.NANOSECONDS);
jaroslav@1890
   235
        }
jaroslav@1890
   236
jaroslav@1890
   237
        public int compareTo(Delayed other) {
jaroslav@1890
   238
            if (other == this) // compare zero ONLY if same object
jaroslav@1890
   239
                return 0;
jaroslav@1890
   240
            if (other instanceof ScheduledFutureTask) {
jaroslav@1890
   241
                ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
jaroslav@1890
   242
                long diff = time - x.time;
jaroslav@1890
   243
                if (diff < 0)
jaroslav@1890
   244
                    return -1;
jaroslav@1890
   245
                else if (diff > 0)
jaroslav@1890
   246
                    return 1;
jaroslav@1890
   247
                else if (sequenceNumber < x.sequenceNumber)
jaroslav@1890
   248
                    return -1;
jaroslav@1890
   249
                else
jaroslav@1890
   250
                    return 1;
jaroslav@1890
   251
            }
jaroslav@1890
   252
            long d = (getDelay(TimeUnit.NANOSECONDS) -
jaroslav@1890
   253
                      other.getDelay(TimeUnit.NANOSECONDS));
jaroslav@1890
   254
            return (d == 0) ? 0 : ((d < 0) ? -1 : 1);
jaroslav@1890
   255
        }
jaroslav@1890
   256
jaroslav@1890
   257
        /**
jaroslav@1890
   258
         * Returns true if this is a periodic (not a one-shot) action.
jaroslav@1890
   259
         *
jaroslav@1890
   260
         * @return true if periodic
jaroslav@1890
   261
         */
jaroslav@1890
   262
        public boolean isPeriodic() {
jaroslav@1890
   263
            return period != 0;
jaroslav@1890
   264
        }
jaroslav@1890
   265
jaroslav@1890
   266
        /**
jaroslav@1890
   267
         * Sets the next time to run for a periodic task.
jaroslav@1890
   268
         */
jaroslav@1890
   269
        private void setNextRunTime() {
jaroslav@1890
   270
            long p = period;
jaroslav@1890
   271
            if (p > 0)
jaroslav@1890
   272
                time += p;
jaroslav@1890
   273
            else
jaroslav@1890
   274
                time = triggerTime(-p);
jaroslav@1890
   275
        }
jaroslav@1890
   276
jaroslav@1890
   277
        public boolean cancel(boolean mayInterruptIfRunning) {
jaroslav@1890
   278
            boolean cancelled = super.cancel(mayInterruptIfRunning);
jaroslav@1890
   279
            if (cancelled && removeOnCancel && heapIndex >= 0)
jaroslav@1890
   280
                remove(this);
jaroslav@1890
   281
            return cancelled;
jaroslav@1890
   282
        }
jaroslav@1890
   283
jaroslav@1890
   284
        /**
jaroslav@1890
   285
         * Overrides FutureTask version so as to reset/requeue if periodic.
jaroslav@1890
   286
         */
jaroslav@1890
   287
        public void run() {
jaroslav@1890
   288
            boolean periodic = isPeriodic();
jaroslav@1890
   289
            if (!canRunInCurrentRunState(periodic))
jaroslav@1890
   290
                cancel(false);
jaroslav@1890
   291
            else if (!periodic)
jaroslav@1890
   292
                ScheduledFutureTask.super.run();
jaroslav@1890
   293
            else if (ScheduledFutureTask.super.runAndReset()) {
jaroslav@1890
   294
                setNextRunTime();
jaroslav@1890
   295
                reExecutePeriodic(outerTask);
jaroslav@1890
   296
            }
jaroslav@1890
   297
        }
jaroslav@1890
   298
    }
jaroslav@1890
   299
jaroslav@1890
   300
    /**
jaroslav@1890
   301
     * Returns true if can run a task given current run state
jaroslav@1890
   302
     * and run-after-shutdown parameters.
jaroslav@1890
   303
     *
jaroslav@1890
   304
     * @param periodic true if this task periodic, false if delayed
jaroslav@1890
   305
     */
jaroslav@1890
   306
    boolean canRunInCurrentRunState(boolean periodic) {
jaroslav@1890
   307
        return isRunningOrShutdown(periodic ?
jaroslav@1890
   308
                                   continueExistingPeriodicTasksAfterShutdown :
jaroslav@1890
   309
                                   executeExistingDelayedTasksAfterShutdown);
jaroslav@1890
   310
    }
jaroslav@1890
   311
jaroslav@1890
   312
    /**
jaroslav@1890
   313
     * Main execution method for delayed or periodic tasks.  If pool
jaroslav@1890
   314
     * is shut down, rejects the task. Otherwise adds task to queue
jaroslav@1890
   315
     * and starts a thread, if necessary, to run it.  (We cannot
jaroslav@1890
   316
     * prestart the thread to run the task because the task (probably)
jaroslav@1890
   317
     * shouldn't be run yet,) If the pool is shut down while the task
jaroslav@1890
   318
     * is being added, cancel and remove it if required by state and
jaroslav@1890
   319
     * run-after-shutdown parameters.
jaroslav@1890
   320
     *
jaroslav@1890
   321
     * @param task the task
jaroslav@1890
   322
     */
jaroslav@1890
   323
    private void delayedExecute(RunnableScheduledFuture<?> task) {
jaroslav@1890
   324
        if (isShutdown())
jaroslav@1890
   325
            reject(task);
jaroslav@1890
   326
        else {
jaroslav@1890
   327
            super.getQueue().add(task);
jaroslav@1890
   328
            if (isShutdown() &&
jaroslav@1890
   329
                !canRunInCurrentRunState(task.isPeriodic()) &&
jaroslav@1890
   330
                remove(task))
jaroslav@1890
   331
                task.cancel(false);
jaroslav@1890
   332
            else
jaroslav@1890
   333
                prestartCoreThread();
jaroslav@1890
   334
        }
jaroslav@1890
   335
    }
jaroslav@1890
   336
jaroslav@1890
   337
    /**
jaroslav@1890
   338
     * Requeues a periodic task unless current run state precludes it.
jaroslav@1890
   339
     * Same idea as delayedExecute except drops task rather than rejecting.
jaroslav@1890
   340
     *
jaroslav@1890
   341
     * @param task the task
jaroslav@1890
   342
     */
jaroslav@1890
   343
    void reExecutePeriodic(RunnableScheduledFuture<?> task) {
jaroslav@1890
   344
        if (canRunInCurrentRunState(true)) {
jaroslav@1890
   345
            super.getQueue().add(task);
jaroslav@1890
   346
            if (!canRunInCurrentRunState(true) && remove(task))
jaroslav@1890
   347
                task.cancel(false);
jaroslav@1890
   348
            else
jaroslav@1890
   349
                prestartCoreThread();
jaroslav@1890
   350
        }
jaroslav@1890
   351
    }
jaroslav@1890
   352
jaroslav@1890
   353
    /**
jaroslav@1890
   354
     * Cancels and clears the queue of all tasks that should not be run
jaroslav@1890
   355
     * due to shutdown policy.  Invoked within super.shutdown.
jaroslav@1890
   356
     */
jaroslav@1890
   357
    @Override void onShutdown() {
jaroslav@1890
   358
        BlockingQueue<Runnable> q = super.getQueue();
jaroslav@1890
   359
        boolean keepDelayed =
jaroslav@1890
   360
            getExecuteExistingDelayedTasksAfterShutdownPolicy();
jaroslav@1890
   361
        boolean keepPeriodic =
jaroslav@1890
   362
            getContinueExistingPeriodicTasksAfterShutdownPolicy();
jaroslav@1890
   363
        if (!keepDelayed && !keepPeriodic) {
jaroslav@1890
   364
            for (Object e : q.toArray())
jaroslav@1890
   365
                if (e instanceof RunnableScheduledFuture<?>)
jaroslav@1890
   366
                    ((RunnableScheduledFuture<?>) e).cancel(false);
jaroslav@1890
   367
            q.clear();
jaroslav@1890
   368
        }
jaroslav@1890
   369
        else {
jaroslav@1890
   370
            // Traverse snapshot to avoid iterator exceptions
jaroslav@1890
   371
            for (Object e : q.toArray()) {
jaroslav@1890
   372
                if (e instanceof RunnableScheduledFuture) {
jaroslav@1890
   373
                    RunnableScheduledFuture<?> t =
jaroslav@1890
   374
                        (RunnableScheduledFuture<?>)e;
jaroslav@1890
   375
                    if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) ||
jaroslav@1890
   376
                        t.isCancelled()) { // also remove if already cancelled
jaroslav@1890
   377
                        if (q.remove(t))
jaroslav@1890
   378
                            t.cancel(false);
jaroslav@1890
   379
                    }
jaroslav@1890
   380
                }
jaroslav@1890
   381
            }
jaroslav@1890
   382
        }
jaroslav@1890
   383
        tryTerminate();
jaroslav@1890
   384
    }
jaroslav@1890
   385
jaroslav@1890
   386
    /**
jaroslav@1890
   387
     * Modifies or replaces the task used to execute a runnable.
jaroslav@1890
   388
     * This method can be used to override the concrete
jaroslav@1890
   389
     * class used for managing internal tasks.
jaroslav@1890
   390
     * The default implementation simply returns the given task.
jaroslav@1890
   391
     *
jaroslav@1890
   392
     * @param runnable the submitted Runnable
jaroslav@1890
   393
     * @param task the task created to execute the runnable
jaroslav@1890
   394
     * @return a task that can execute the runnable
jaroslav@1890
   395
     * @since 1.6
jaroslav@1890
   396
     */
jaroslav@1890
   397
    protected <V> RunnableScheduledFuture<V> decorateTask(
jaroslav@1890
   398
        Runnable runnable, RunnableScheduledFuture<V> task) {
jaroslav@1890
   399
        return task;
jaroslav@1890
   400
    }
jaroslav@1890
   401
jaroslav@1890
   402
    /**
jaroslav@1890
   403
     * Modifies or replaces the task used to execute a callable.
jaroslav@1890
   404
     * This method can be used to override the concrete
jaroslav@1890
   405
     * class used for managing internal tasks.
jaroslav@1890
   406
     * The default implementation simply returns the given task.
jaroslav@1890
   407
     *
jaroslav@1890
   408
     * @param callable the submitted Callable
jaroslav@1890
   409
     * @param task the task created to execute the callable
jaroslav@1890
   410
     * @return a task that can execute the callable
jaroslav@1890
   411
     * @since 1.6
jaroslav@1890
   412
     */
jaroslav@1890
   413
    protected <V> RunnableScheduledFuture<V> decorateTask(
jaroslav@1890
   414
        Callable<V> callable, RunnableScheduledFuture<V> task) {
jaroslav@1890
   415
        return task;
jaroslav@1890
   416
    }
jaroslav@1890
   417
jaroslav@1890
   418
    /**
jaroslav@1890
   419
     * Creates a new {@code ScheduledThreadPoolExecutor} with the
jaroslav@1890
   420
     * given core pool size.
jaroslav@1890
   421
     *
jaroslav@1890
   422
     * @param corePoolSize the number of threads to keep in the pool, even
jaroslav@1890
   423
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
jaroslav@1890
   424
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
jaroslav@1890
   425
     */
jaroslav@1890
   426
    public ScheduledThreadPoolExecutor(int corePoolSize) {
jaroslav@1890
   427
        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
jaroslav@1890
   428
              new DelayedWorkQueue());
jaroslav@1890
   429
    }
jaroslav@1890
   430
jaroslav@1890
   431
    /**
jaroslav@1890
   432
     * Creates a new {@code ScheduledThreadPoolExecutor} with the
jaroslav@1890
   433
     * given initial parameters.
jaroslav@1890
   434
     *
jaroslav@1890
   435
     * @param corePoolSize the number of threads to keep in the pool, even
jaroslav@1890
   436
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
jaroslav@1890
   437
     * @param threadFactory the factory to use when the executor
jaroslav@1890
   438
     *        creates a new thread
jaroslav@1890
   439
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
jaroslav@1890
   440
     * @throws NullPointerException if {@code threadFactory} is null
jaroslav@1890
   441
     */
jaroslav@1890
   442
    public ScheduledThreadPoolExecutor(int corePoolSize,
jaroslav@1890
   443
                                       ThreadFactory threadFactory) {
jaroslav@1890
   444
        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
jaroslav@1890
   445
              new DelayedWorkQueue(), threadFactory);
jaroslav@1890
   446
    }
jaroslav@1890
   447
jaroslav@1890
   448
    /**
jaroslav@1890
   449
     * Creates a new ScheduledThreadPoolExecutor with the given
jaroslav@1890
   450
     * initial parameters.
jaroslav@1890
   451
     *
jaroslav@1890
   452
     * @param corePoolSize the number of threads to keep in the pool, even
jaroslav@1890
   453
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
jaroslav@1890
   454
     * @param handler the handler to use when execution is blocked
jaroslav@1890
   455
     *        because the thread bounds and queue capacities are reached
jaroslav@1890
   456
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
jaroslav@1890
   457
     * @throws NullPointerException if {@code handler} is null
jaroslav@1890
   458
     */
jaroslav@1890
   459
    public ScheduledThreadPoolExecutor(int corePoolSize,
jaroslav@1890
   460
                                       RejectedExecutionHandler handler) {
jaroslav@1890
   461
        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
jaroslav@1890
   462
              new DelayedWorkQueue(), handler);
jaroslav@1890
   463
    }
jaroslav@1890
   464
jaroslav@1890
   465
    /**
jaroslav@1890
   466
     * Creates a new ScheduledThreadPoolExecutor with the given
jaroslav@1890
   467
     * initial parameters.
jaroslav@1890
   468
     *
jaroslav@1890
   469
     * @param corePoolSize the number of threads to keep in the pool, even
jaroslav@1890
   470
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
jaroslav@1890
   471
     * @param threadFactory the factory to use when the executor
jaroslav@1890
   472
     *        creates a new thread
jaroslav@1890
   473
     * @param handler the handler to use when execution is blocked
jaroslav@1890
   474
     *        because the thread bounds and queue capacities are reached
jaroslav@1890
   475
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
jaroslav@1890
   476
     * @throws NullPointerException if {@code threadFactory} or
jaroslav@1890
   477
     *         {@code handler} is null
jaroslav@1890
   478
     */
jaroslav@1890
   479
    public ScheduledThreadPoolExecutor(int corePoolSize,
jaroslav@1890
   480
                                       ThreadFactory threadFactory,
jaroslav@1890
   481
                                       RejectedExecutionHandler handler) {
jaroslav@1890
   482
        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
jaroslav@1890
   483
              new DelayedWorkQueue(), threadFactory, handler);
jaroslav@1890
   484
    }
jaroslav@1890
   485
jaroslav@1890
   486
    /**
jaroslav@1890
   487
     * Returns the trigger time of a delayed action.
jaroslav@1890
   488
     */
jaroslav@1890
   489
    private long triggerTime(long delay, TimeUnit unit) {
jaroslav@1890
   490
        return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
jaroslav@1890
   491
    }
jaroslav@1890
   492
jaroslav@1890
   493
    /**
jaroslav@1890
   494
     * Returns the trigger time of a delayed action.
jaroslav@1890
   495
     */
jaroslav@1890
   496
    long triggerTime(long delay) {
jaroslav@1890
   497
        return now() +
jaroslav@1890
   498
            ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
jaroslav@1890
   499
    }
jaroslav@1890
   500
jaroslav@1890
   501
    /**
jaroslav@1890
   502
     * Constrains the values of all delays in the queue to be within
jaroslav@1890
   503
     * Long.MAX_VALUE of each other, to avoid overflow in compareTo.
jaroslav@1890
   504
     * This may occur if a task is eligible to be dequeued, but has
jaroslav@1890
   505
     * not yet been, while some other task is added with a delay of
jaroslav@1890
   506
     * Long.MAX_VALUE.
jaroslav@1890
   507
     */
jaroslav@1890
   508
    private long overflowFree(long delay) {
jaroslav@1890
   509
        Delayed head = (Delayed) super.getQueue().peek();
jaroslav@1890
   510
        if (head != null) {
jaroslav@1890
   511
            long headDelay = head.getDelay(TimeUnit.NANOSECONDS);
jaroslav@1890
   512
            if (headDelay < 0 && (delay - headDelay < 0))
jaroslav@1890
   513
                delay = Long.MAX_VALUE + headDelay;
jaroslav@1890
   514
        }
jaroslav@1890
   515
        return delay;
jaroslav@1890
   516
    }
jaroslav@1890
   517
jaroslav@1890
   518
    /**
jaroslav@1890
   519
     * @throws RejectedExecutionException {@inheritDoc}
jaroslav@1890
   520
     * @throws NullPointerException       {@inheritDoc}
jaroslav@1890
   521
     */
jaroslav@1890
   522
    public ScheduledFuture<?> schedule(Runnable command,
jaroslav@1890
   523
                                       long delay,
jaroslav@1890
   524
                                       TimeUnit unit) {
jaroslav@1890
   525
        if (command == null || unit == null)
jaroslav@1890
   526
            throw new NullPointerException();
jaroslav@1890
   527
        RunnableScheduledFuture<?> t = decorateTask(command,
jaroslav@1890
   528
            new ScheduledFutureTask<Void>(command, null,
jaroslav@1890
   529
                                          triggerTime(delay, unit)));
jaroslav@1890
   530
        delayedExecute(t);
jaroslav@1890
   531
        return t;
jaroslav@1890
   532
    }
jaroslav@1890
   533
jaroslav@1890
   534
    /**
jaroslav@1890
   535
     * @throws RejectedExecutionException {@inheritDoc}
jaroslav@1890
   536
     * @throws NullPointerException       {@inheritDoc}
jaroslav@1890
   537
     */
jaroslav@1890
   538
    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
jaroslav@1890
   539
                                           long delay,
jaroslav@1890
   540
                                           TimeUnit unit) {
jaroslav@1890
   541
        if (callable == null || unit == null)
jaroslav@1890
   542
            throw new NullPointerException();
jaroslav@1890
   543
        RunnableScheduledFuture<V> t = decorateTask(callable,
jaroslav@1890
   544
            new ScheduledFutureTask<V>(callable,
jaroslav@1890
   545
                                       triggerTime(delay, unit)));
jaroslav@1890
   546
        delayedExecute(t);
jaroslav@1890
   547
        return t;
jaroslav@1890
   548
    }
jaroslav@1890
   549
jaroslav@1890
   550
    /**
jaroslav@1890
   551
     * @throws RejectedExecutionException {@inheritDoc}
jaroslav@1890
   552
     * @throws NullPointerException       {@inheritDoc}
jaroslav@1890
   553
     * @throws IllegalArgumentException   {@inheritDoc}
jaroslav@1890
   554
     */
jaroslav@1890
   555
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
jaroslav@1890
   556
                                                  long initialDelay,
jaroslav@1890
   557
                                                  long period,
jaroslav@1890
   558
                                                  TimeUnit unit) {
jaroslav@1890
   559
        if (command == null || unit == null)
jaroslav@1890
   560
            throw new NullPointerException();
jaroslav@1890
   561
        if (period <= 0)
jaroslav@1890
   562
            throw new IllegalArgumentException();
jaroslav@1890
   563
        ScheduledFutureTask<Void> sft =
jaroslav@1890
   564
            new ScheduledFutureTask<Void>(command,
jaroslav@1890
   565
                                          null,
jaroslav@1890
   566
                                          triggerTime(initialDelay, unit),
jaroslav@1890
   567
                                          unit.toNanos(period));
jaroslav@1890
   568
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
jaroslav@1890
   569
        sft.outerTask = t;
jaroslav@1890
   570
        delayedExecute(t);
jaroslav@1890
   571
        return t;
jaroslav@1890
   572
    }
jaroslav@1890
   573
jaroslav@1890
   574
    /**
jaroslav@1890
   575
     * @throws RejectedExecutionException {@inheritDoc}
jaroslav@1890
   576
     * @throws NullPointerException       {@inheritDoc}
jaroslav@1890
   577
     * @throws IllegalArgumentException   {@inheritDoc}
jaroslav@1890
   578
     */
jaroslav@1890
   579
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
jaroslav@1890
   580
                                                     long initialDelay,
jaroslav@1890
   581
                                                     long delay,
jaroslav@1890
   582
                                                     TimeUnit unit) {
jaroslav@1890
   583
        if (command == null || unit == null)
jaroslav@1890
   584
            throw new NullPointerException();
jaroslav@1890
   585
        if (delay <= 0)
jaroslav@1890
   586
            throw new IllegalArgumentException();
jaroslav@1890
   587
        ScheduledFutureTask<Void> sft =
jaroslav@1890
   588
            new ScheduledFutureTask<Void>(command,
jaroslav@1890
   589
                                          null,
jaroslav@1890
   590
                                          triggerTime(initialDelay, unit),
jaroslav@1890
   591
                                          unit.toNanos(-delay));
jaroslav@1890
   592
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
jaroslav@1890
   593
        sft.outerTask = t;
jaroslav@1890
   594
        delayedExecute(t);
jaroslav@1890
   595
        return t;
jaroslav@1890
   596
    }
jaroslav@1890
   597
jaroslav@1890
   598
    /**
jaroslav@1890
   599
     * Executes {@code command} with zero required delay.
jaroslav@1890
   600
     * This has effect equivalent to
jaroslav@1890
   601
     * {@link #schedule(Runnable,long,TimeUnit) schedule(command, 0, anyUnit)}.
jaroslav@1890
   602
     * Note that inspections of the queue and of the list returned by
jaroslav@1890
   603
     * {@code shutdownNow} will access the zero-delayed
jaroslav@1890
   604
     * {@link ScheduledFuture}, not the {@code command} itself.
jaroslav@1890
   605
     *
jaroslav@1890
   606
     * <p>A consequence of the use of {@code ScheduledFuture} objects is
jaroslav@1890
   607
     * that {@link ThreadPoolExecutor#afterExecute afterExecute} is always
jaroslav@1890
   608
     * called with a null second {@code Throwable} argument, even if the
jaroslav@1890
   609
     * {@code command} terminated abruptly.  Instead, the {@code Throwable}
jaroslav@1890
   610
     * thrown by such a task can be obtained via {@link Future#get}.
jaroslav@1890
   611
     *
jaroslav@1890
   612
     * @throws RejectedExecutionException at discretion of
jaroslav@1890
   613
     *         {@code RejectedExecutionHandler}, if the task
jaroslav@1890
   614
     *         cannot be accepted for execution because the
jaroslav@1890
   615
     *         executor has been shut down
jaroslav@1890
   616
     * @throws NullPointerException {@inheritDoc}
jaroslav@1890
   617
     */
jaroslav@1890
   618
    public void execute(Runnable command) {
jaroslav@1890
   619
        schedule(command, 0, TimeUnit.NANOSECONDS);
jaroslav@1890
   620
    }
jaroslav@1890
   621
jaroslav@1890
   622
    // Override AbstractExecutorService methods
jaroslav@1890
   623
jaroslav@1890
   624
    /**
jaroslav@1890
   625
     * @throws RejectedExecutionException {@inheritDoc}
jaroslav@1890
   626
     * @throws NullPointerException       {@inheritDoc}
jaroslav@1890
   627
     */
jaroslav@1890
   628
    public Future<?> submit(Runnable task) {
jaroslav@1890
   629
        return schedule(task, 0, TimeUnit.NANOSECONDS);
jaroslav@1890
   630
    }
jaroslav@1890
   631
jaroslav@1890
   632
    /**
jaroslav@1890
   633
     * @throws RejectedExecutionException {@inheritDoc}
jaroslav@1890
   634
     * @throws NullPointerException       {@inheritDoc}
jaroslav@1890
   635
     */
jaroslav@1890
   636
    public <T> Future<T> submit(Runnable task, T result) {
jaroslav@1890
   637
        return schedule(Executors.callable(task, result),
jaroslav@1890
   638
                        0, TimeUnit.NANOSECONDS);
jaroslav@1890
   639
    }
jaroslav@1890
   640
jaroslav@1890
   641
    /**
jaroslav@1890
   642
     * @throws RejectedExecutionException {@inheritDoc}
jaroslav@1890
   643
     * @throws NullPointerException       {@inheritDoc}
jaroslav@1890
   644
     */
jaroslav@1890
   645
    public <T> Future<T> submit(Callable<T> task) {
jaroslav@1890
   646
        return schedule(task, 0, TimeUnit.NANOSECONDS);
jaroslav@1890
   647
    }
jaroslav@1890
   648
jaroslav@1890
   649
    /**
jaroslav@1890
   650
     * Sets the policy on whether to continue executing existing
jaroslav@1890
   651
     * periodic tasks even when this executor has been {@code shutdown}.
jaroslav@1890
   652
     * In this case, these tasks will only terminate upon
jaroslav@1890
   653
     * {@code shutdownNow} or after setting the policy to
jaroslav@1890
   654
     * {@code false} when already shutdown.
jaroslav@1890
   655
     * This value is by default {@code false}.
jaroslav@1890
   656
     *
jaroslav@1890
   657
     * @param value if {@code true}, continue after shutdown, else don't.
jaroslav@1890
   658
     * @see #getContinueExistingPeriodicTasksAfterShutdownPolicy
jaroslav@1890
   659
     */
jaroslav@1890
   660
    public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) {
jaroslav@1890
   661
        continueExistingPeriodicTasksAfterShutdown = value;
jaroslav@1890
   662
        if (!value && isShutdown())
jaroslav@1890
   663
            onShutdown();
jaroslav@1890
   664
    }
jaroslav@1890
   665
jaroslav@1890
   666
    /**
jaroslav@1890
   667
     * Gets the policy on whether to continue executing existing
jaroslav@1890
   668
     * periodic tasks even when this executor has been {@code shutdown}.
jaroslav@1890
   669
     * In this case, these tasks will only terminate upon
jaroslav@1890
   670
     * {@code shutdownNow} or after setting the policy to
jaroslav@1890
   671
     * {@code false} when already shutdown.
jaroslav@1890
   672
     * This value is by default {@code false}.
jaroslav@1890
   673
     *
jaroslav@1890
   674
     * @return {@code true} if will continue after shutdown
jaroslav@1890
   675
     * @see #setContinueExistingPeriodicTasksAfterShutdownPolicy
jaroslav@1890
   676
     */
jaroslav@1890
   677
    public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() {
jaroslav@1890
   678
        return continueExistingPeriodicTasksAfterShutdown;
jaroslav@1890
   679
    }
jaroslav@1890
   680
jaroslav@1890
   681
    /**
jaroslav@1890
   682
     * Sets the policy on whether to execute existing delayed
jaroslav@1890
   683
     * tasks even when this executor has been {@code shutdown}.
jaroslav@1890
   684
     * In this case, these tasks will only terminate upon
jaroslav@1890
   685
     * {@code shutdownNow}, or after setting the policy to
jaroslav@1890
   686
     * {@code false} when already shutdown.
jaroslav@1890
   687
     * This value is by default {@code true}.
jaroslav@1890
   688
     *
jaroslav@1890
   689
     * @param value if {@code true}, execute after shutdown, else don't.
jaroslav@1890
   690
     * @see #getExecuteExistingDelayedTasksAfterShutdownPolicy
jaroslav@1890
   691
     */
jaroslav@1890
   692
    public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) {
jaroslav@1890
   693
        executeExistingDelayedTasksAfterShutdown = value;
jaroslav@1890
   694
        if (!value && isShutdown())
jaroslav@1890
   695
            onShutdown();
jaroslav@1890
   696
    }
jaroslav@1890
   697
jaroslav@1890
   698
    /**
jaroslav@1890
   699
     * Gets the policy on whether to execute existing delayed
jaroslav@1890
   700
     * tasks even when this executor has been {@code shutdown}.
jaroslav@1890
   701
     * In this case, these tasks will only terminate upon
jaroslav@1890
   702
     * {@code shutdownNow}, or after setting the policy to
jaroslav@1890
   703
     * {@code false} when already shutdown.
jaroslav@1890
   704
     * This value is by default {@code true}.
jaroslav@1890
   705
     *
jaroslav@1890
   706
     * @return {@code true} if will execute after shutdown
jaroslav@1890
   707
     * @see #setExecuteExistingDelayedTasksAfterShutdownPolicy
jaroslav@1890
   708
     */
jaroslav@1890
   709
    public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() {
jaroslav@1890
   710
        return executeExistingDelayedTasksAfterShutdown;
jaroslav@1890
   711
    }
jaroslav@1890
   712
jaroslav@1890
   713
    /**
jaroslav@1890
   714
     * Sets the policy on whether cancelled tasks should be immediately
jaroslav@1890
   715
     * removed from the work queue at time of cancellation.  This value is
jaroslav@1890
   716
     * by default {@code false}.
jaroslav@1890
   717
     *
jaroslav@1890
   718
     * @param value if {@code true}, remove on cancellation, else don't
jaroslav@1890
   719
     * @see #getRemoveOnCancelPolicy
jaroslav@1890
   720
     * @since 1.7
jaroslav@1890
   721
     */
jaroslav@1890
   722
    public void setRemoveOnCancelPolicy(boolean value) {
jaroslav@1890
   723
        removeOnCancel = value;
jaroslav@1890
   724
    }
jaroslav@1890
   725
jaroslav@1890
   726
    /**
jaroslav@1890
   727
     * Gets the policy on whether cancelled tasks should be immediately
jaroslav@1890
   728
     * removed from the work queue at time of cancellation.  This value is
jaroslav@1890
   729
     * by default {@code false}.
jaroslav@1890
   730
     *
jaroslav@1890
   731
     * @return {@code true} if cancelled tasks are immediately removed
jaroslav@1890
   732
     *         from the queue
jaroslav@1890
   733
     * @see #setRemoveOnCancelPolicy
jaroslav@1890
   734
     * @since 1.7
jaroslav@1890
   735
     */
jaroslav@1890
   736
    public boolean getRemoveOnCancelPolicy() {
jaroslav@1890
   737
        return removeOnCancel;
jaroslav@1890
   738
    }
jaroslav@1890
   739
jaroslav@1890
   740
    /**
jaroslav@1890
   741
     * Initiates an orderly shutdown in which previously submitted
jaroslav@1890
   742
     * tasks are executed, but no new tasks will be accepted.
jaroslav@1890
   743
     * Invocation has no additional effect if already shut down.
jaroslav@1890
   744
     *
jaroslav@1890
   745
     * <p>This method does not wait for previously submitted tasks to
jaroslav@1890
   746
     * complete execution.  Use {@link #awaitTermination awaitTermination}
jaroslav@1890
   747
     * to do that.
jaroslav@1890
   748
     *
jaroslav@1890
   749
     * <p>If the {@code ExecuteExistingDelayedTasksAfterShutdownPolicy}
jaroslav@1890
   750
     * has been set {@code false}, existing delayed tasks whose delays
jaroslav@1890
   751
     * have not yet elapsed are cancelled.  And unless the {@code
jaroslav@1890
   752
     * ContinueExistingPeriodicTasksAfterShutdownPolicy} has been set
jaroslav@1890
   753
     * {@code true}, future executions of existing periodic tasks will
jaroslav@1890
   754
     * be cancelled.
jaroslav@1890
   755
     *
jaroslav@1890
   756
     * @throws SecurityException {@inheritDoc}
jaroslav@1890
   757
     */
jaroslav@1890
   758
    public void shutdown() {
jaroslav@1890
   759
        super.shutdown();
jaroslav@1890
   760
    }
jaroslav@1890
   761
jaroslav@1890
   762
    /**
jaroslav@1890
   763
     * Attempts to stop all actively executing tasks, halts the
jaroslav@1890
   764
     * processing of waiting tasks, and returns a list of the tasks
jaroslav@1890
   765
     * that were awaiting execution.
jaroslav@1890
   766
     *
jaroslav@1890
   767
     * <p>This method does not wait for actively executing tasks to
jaroslav@1890
   768
     * terminate.  Use {@link #awaitTermination awaitTermination} to
jaroslav@1890
   769
     * do that.
jaroslav@1890
   770
     *
jaroslav@1890
   771
     * <p>There are no guarantees beyond best-effort attempts to stop
jaroslav@1890
   772
     * processing actively executing tasks.  This implementation
jaroslav@1890
   773
     * cancels tasks via {@link Thread#interrupt}, so any task that
jaroslav@1890
   774
     * fails to respond to interrupts may never terminate.
jaroslav@1890
   775
     *
jaroslav@1890
   776
     * @return list of tasks that never commenced execution.
jaroslav@1890
   777
     *         Each element of this list is a {@link ScheduledFuture},
jaroslav@1890
   778
     *         including those tasks submitted using {@code execute},
jaroslav@1890
   779
     *         which are for scheduling purposes used as the basis of a
jaroslav@1890
   780
     *         zero-delay {@code ScheduledFuture}.
jaroslav@1890
   781
     * @throws SecurityException {@inheritDoc}
jaroslav@1890
   782
     */
jaroslav@1890
   783
    public List<Runnable> shutdownNow() {
jaroslav@1890
   784
        return super.shutdownNow();
jaroslav@1890
   785
    }
jaroslav@1890
   786
jaroslav@1890
   787
    /**
jaroslav@1890
   788
     * Returns the task queue used by this executor.  Each element of
jaroslav@1890
   789
     * this queue is a {@link ScheduledFuture}, including those
jaroslav@1890
   790
     * tasks submitted using {@code execute} which are for scheduling
jaroslav@1890
   791
     * purposes used as the basis of a zero-delay
jaroslav@1890
   792
     * {@code ScheduledFuture}.  Iteration over this queue is
jaroslav@1890
   793
     * <em>not</em> guaranteed to traverse tasks in the order in
jaroslav@1890
   794
     * which they will execute.
jaroslav@1890
   795
     *
jaroslav@1890
   796
     * @return the task queue
jaroslav@1890
   797
     */
jaroslav@1890
   798
    public BlockingQueue<Runnable> getQueue() {
jaroslav@1890
   799
        return super.getQueue();
jaroslav@1890
   800
    }
jaroslav@1890
   801
jaroslav@1890
   802
    /**
jaroslav@1890
   803
     * Specialized delay queue. To mesh with TPE declarations, this
jaroslav@1890
   804
     * class must be declared as a BlockingQueue<Runnable> even though
jaroslav@1890
   805
     * it can only hold RunnableScheduledFutures.
jaroslav@1890
   806
     */
jaroslav@1890
   807
    static class DelayedWorkQueue extends AbstractQueue<Runnable>
jaroslav@1890
   808
        implements BlockingQueue<Runnable> {
jaroslav@1890
   809
jaroslav@1890
   810
        /*
jaroslav@1890
   811
         * A DelayedWorkQueue is based on a heap-based data structure
jaroslav@1890
   812
         * like those in DelayQueue and PriorityQueue, except that
jaroslav@1890
   813
         * every ScheduledFutureTask also records its index into the
jaroslav@1890
   814
         * heap array. This eliminates the need to find a task upon
jaroslav@1890
   815
         * cancellation, greatly speeding up removal (down from O(n)
jaroslav@1890
   816
         * to O(log n)), and reducing garbage retention that would
jaroslav@1890
   817
         * otherwise occur by waiting for the element to rise to top
jaroslav@1890
   818
         * before clearing. But because the queue may also hold
jaroslav@1890
   819
         * RunnableScheduledFutures that are not ScheduledFutureTasks,
jaroslav@1890
   820
         * we are not guaranteed to have such indices available, in
jaroslav@1890
   821
         * which case we fall back to linear search. (We expect that
jaroslav@1890
   822
         * most tasks will not be decorated, and that the faster cases
jaroslav@1890
   823
         * will be much more common.)
jaroslav@1890
   824
         *
jaroslav@1890
   825
         * All heap operations must record index changes -- mainly
jaroslav@1890
   826
         * within siftUp and siftDown. Upon removal, a task's
jaroslav@1890
   827
         * heapIndex is set to -1. Note that ScheduledFutureTasks can
jaroslav@1890
   828
         * appear at most once in the queue (this need not be true for
jaroslav@1890
   829
         * other kinds of tasks or work queues), so are uniquely
jaroslav@1890
   830
         * identified by heapIndex.
jaroslav@1890
   831
         */
jaroslav@1890
   832
jaroslav@1890
   833
        private static final int INITIAL_CAPACITY = 16;
jaroslav@1890
   834
        private RunnableScheduledFuture[] queue =
jaroslav@1890
   835
            new RunnableScheduledFuture[INITIAL_CAPACITY];
jaroslav@1890
   836
        private final ReentrantLock lock = new ReentrantLock();
jaroslav@1890
   837
        private int size = 0;
jaroslav@1890
   838
jaroslav@1890
   839
        /**
jaroslav@1890
   840
         * Thread designated to wait for the task at the head of the
jaroslav@1890
   841
         * queue.  This variant of the Leader-Follower pattern
jaroslav@1890
   842
         * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to
jaroslav@1890
   843
         * minimize unnecessary timed waiting.  When a thread becomes
jaroslav@1890
   844
         * the leader, it waits only for the next delay to elapse, but
jaroslav@1890
   845
         * other threads await indefinitely.  The leader thread must
jaroslav@1890
   846
         * signal some other thread before returning from take() or
jaroslav@1890
   847
         * poll(...), unless some other thread becomes leader in the
jaroslav@1890
   848
         * interim.  Whenever the head of the queue is replaced with a
jaroslav@1890
   849
         * task with an earlier expiration time, the leader field is
jaroslav@1890
   850
         * invalidated by being reset to null, and some waiting
jaroslav@1890
   851
         * thread, but not necessarily the current leader, is
jaroslav@1890
   852
         * signalled.  So waiting threads must be prepared to acquire
jaroslav@1890
   853
         * and lose leadership while waiting.
jaroslav@1890
   854
         */
jaroslav@1890
   855
        private Thread leader = null;
jaroslav@1890
   856
jaroslav@1890
   857
        /**
jaroslav@1890
   858
         * Condition signalled when a newer task becomes available at the
jaroslav@1890
   859
         * head of the queue or a new thread may need to become leader.
jaroslav@1890
   860
         */
jaroslav@1890
   861
        private final Condition available = lock.newCondition();
jaroslav@1890
   862
jaroslav@1890
   863
        /**
jaroslav@1890
   864
         * Set f's heapIndex if it is a ScheduledFutureTask.
jaroslav@1890
   865
         */
jaroslav@1890
   866
        private void setIndex(RunnableScheduledFuture f, int idx) {
jaroslav@1890
   867
            if (f instanceof ScheduledFutureTask)
jaroslav@1890
   868
                ((ScheduledFutureTask)f).heapIndex = idx;
jaroslav@1890
   869
        }
jaroslav@1890
   870
jaroslav@1890
   871
        /**
jaroslav@1890
   872
         * Sift element added at bottom up to its heap-ordered spot.
jaroslav@1890
   873
         * Call only when holding lock.
jaroslav@1890
   874
         */
jaroslav@1890
   875
        private void siftUp(int k, RunnableScheduledFuture key) {
jaroslav@1890
   876
            while (k > 0) {
jaroslav@1890
   877
                int parent = (k - 1) >>> 1;
jaroslav@1890
   878
                RunnableScheduledFuture e = queue[parent];
jaroslav@1890
   879
                if (key.compareTo(e) >= 0)
jaroslav@1890
   880
                    break;
jaroslav@1890
   881
                queue[k] = e;
jaroslav@1890
   882
                setIndex(e, k);
jaroslav@1890
   883
                k = parent;
jaroslav@1890
   884
            }
jaroslav@1890
   885
            queue[k] = key;
jaroslav@1890
   886
            setIndex(key, k);
jaroslav@1890
   887
        }
jaroslav@1890
   888
jaroslav@1890
   889
        /**
jaroslav@1890
   890
         * Sift element added at top down to its heap-ordered spot.
jaroslav@1890
   891
         * Call only when holding lock.
jaroslav@1890
   892
         */
jaroslav@1890
   893
        private void siftDown(int k, RunnableScheduledFuture key) {
jaroslav@1890
   894
            int half = size >>> 1;
jaroslav@1890
   895
            while (k < half) {
jaroslav@1890
   896
                int child = (k << 1) + 1;
jaroslav@1890
   897
                RunnableScheduledFuture c = queue[child];
jaroslav@1890
   898
                int right = child + 1;
jaroslav@1890
   899
                if (right < size && c.compareTo(queue[right]) > 0)
jaroslav@1890
   900
                    c = queue[child = right];
jaroslav@1890
   901
                if (key.compareTo(c) <= 0)
jaroslav@1890
   902
                    break;
jaroslav@1890
   903
                queue[k] = c;
jaroslav@1890
   904
                setIndex(c, k);
jaroslav@1890
   905
                k = child;
jaroslav@1890
   906
            }
jaroslav@1890
   907
            queue[k] = key;
jaroslav@1890
   908
            setIndex(key, k);
jaroslav@1890
   909
        }
jaroslav@1890
   910
jaroslav@1890
   911
        /**
jaroslav@1890
   912
         * Resize the heap array.  Call only when holding lock.
jaroslav@1890
   913
         */
jaroslav@1890
   914
        private void grow() {
jaroslav@1890
   915
            int oldCapacity = queue.length;
jaroslav@1890
   916
            int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50%
jaroslav@1890
   917
            if (newCapacity < 0) // overflow
jaroslav@1890
   918
                newCapacity = Integer.MAX_VALUE;
jaroslav@1890
   919
            queue = Arrays.copyOf(queue, newCapacity);
jaroslav@1890
   920
        }
jaroslav@1890
   921
jaroslav@1890
   922
        /**
jaroslav@1890
   923
         * Find index of given object, or -1 if absent
jaroslav@1890
   924
         */
jaroslav@1890
   925
        private int indexOf(Object x) {
jaroslav@1890
   926
            if (x != null) {
jaroslav@1890
   927
                if (x instanceof ScheduledFutureTask) {
jaroslav@1890
   928
                    int i = ((ScheduledFutureTask) x).heapIndex;
jaroslav@1890
   929
                    // Sanity check; x could conceivably be a
jaroslav@1890
   930
                    // ScheduledFutureTask from some other pool.
jaroslav@1890
   931
                    if (i >= 0 && i < size && queue[i] == x)
jaroslav@1890
   932
                        return i;
jaroslav@1890
   933
                } else {
jaroslav@1890
   934
                    for (int i = 0; i < size; i++)
jaroslav@1890
   935
                        if (x.equals(queue[i]))
jaroslav@1890
   936
                            return i;
jaroslav@1890
   937
                }
jaroslav@1890
   938
            }
jaroslav@1890
   939
            return -1;
jaroslav@1890
   940
        }
jaroslav@1890
   941
jaroslav@1890
   942
        public boolean contains(Object x) {
jaroslav@1890
   943
            final ReentrantLock lock = this.lock;
jaroslav@1890
   944
            lock.lock();
jaroslav@1890
   945
            try {
jaroslav@1890
   946
                return indexOf(x) != -1;
jaroslav@1890
   947
            } finally {
jaroslav@1890
   948
                lock.unlock();
jaroslav@1890
   949
            }
jaroslav@1890
   950
        }
jaroslav@1890
   951
jaroslav@1890
   952
        public boolean remove(Object x) {
jaroslav@1890
   953
            final ReentrantLock lock = this.lock;
jaroslav@1890
   954
            lock.lock();
jaroslav@1890
   955
            try {
jaroslav@1890
   956
                int i = indexOf(x);
jaroslav@1890
   957
                if (i < 0)
jaroslav@1890
   958
                    return false;
jaroslav@1890
   959
jaroslav@1890
   960
                setIndex(queue[i], -1);
jaroslav@1890
   961
                int s = --size;
jaroslav@1890
   962
                RunnableScheduledFuture replacement = queue[s];
jaroslav@1890
   963
                queue[s] = null;
jaroslav@1890
   964
                if (s != i) {
jaroslav@1890
   965
                    siftDown(i, replacement);
jaroslav@1890
   966
                    if (queue[i] == replacement)
jaroslav@1890
   967
                        siftUp(i, replacement);
jaroslav@1890
   968
                }
jaroslav@1890
   969
                return true;
jaroslav@1890
   970
            } finally {
jaroslav@1890
   971
                lock.unlock();
jaroslav@1890
   972
            }
jaroslav@1890
   973
        }
jaroslav@1890
   974
jaroslav@1890
   975
        public int size() {
jaroslav@1890
   976
            final ReentrantLock lock = this.lock;
jaroslav@1890
   977
            lock.lock();
jaroslav@1890
   978
            try {
jaroslav@1890
   979
                return size;
jaroslav@1890
   980
            } finally {
jaroslav@1890
   981
                lock.unlock();
jaroslav@1890
   982
            }
jaroslav@1890
   983
        }
jaroslav@1890
   984
jaroslav@1890
   985
        public boolean isEmpty() {
jaroslav@1890
   986
            return size() == 0;
jaroslav@1890
   987
        }
jaroslav@1890
   988
jaroslav@1890
   989
        public int remainingCapacity() {
jaroslav@1890
   990
            return Integer.MAX_VALUE;
jaroslav@1890
   991
        }
jaroslav@1890
   992
jaroslav@1890
   993
        public RunnableScheduledFuture peek() {
jaroslav@1890
   994
            final ReentrantLock lock = this.lock;
jaroslav@1890
   995
            lock.lock();
jaroslav@1890
   996
            try {
jaroslav@1890
   997
                return queue[0];
jaroslav@1890
   998
            } finally {
jaroslav@1890
   999
                lock.unlock();
jaroslav@1890
  1000
            }
jaroslav@1890
  1001
        }
jaroslav@1890
  1002
jaroslav@1890
  1003
        public boolean offer(Runnable x) {
jaroslav@1890
  1004
            if (x == null)
jaroslav@1890
  1005
                throw new NullPointerException();
jaroslav@1890
  1006
            RunnableScheduledFuture e = (RunnableScheduledFuture)x;
jaroslav@1890
  1007
            final ReentrantLock lock = this.lock;
jaroslav@1890
  1008
            lock.lock();
jaroslav@1890
  1009
            try {
jaroslav@1890
  1010
                int i = size;
jaroslav@1890
  1011
                if (i >= queue.length)
jaroslav@1890
  1012
                    grow();
jaroslav@1890
  1013
                size = i + 1;
jaroslav@1890
  1014
                if (i == 0) {
jaroslav@1890
  1015
                    queue[0] = e;
jaroslav@1890
  1016
                    setIndex(e, 0);
jaroslav@1890
  1017
                } else {
jaroslav@1890
  1018
                    siftUp(i, e);
jaroslav@1890
  1019
                }
jaroslav@1890
  1020
                if (queue[0] == e) {
jaroslav@1890
  1021
                    leader = null;
jaroslav@1890
  1022
                    available.signal();
jaroslav@1890
  1023
                }
jaroslav@1890
  1024
            } finally {
jaroslav@1890
  1025
                lock.unlock();
jaroslav@1890
  1026
            }
jaroslav@1890
  1027
            return true;
jaroslav@1890
  1028
        }
jaroslav@1890
  1029
jaroslav@1890
  1030
        public void put(Runnable e) {
jaroslav@1890
  1031
            offer(e);
jaroslav@1890
  1032
        }
jaroslav@1890
  1033
jaroslav@1890
  1034
        public boolean add(Runnable e) {
jaroslav@1890
  1035
            return offer(e);
jaroslav@1890
  1036
        }
jaroslav@1890
  1037
jaroslav@1890
  1038
        public boolean offer(Runnable e, long timeout, TimeUnit unit) {
jaroslav@1890
  1039
            return offer(e);
jaroslav@1890
  1040
        }
jaroslav@1890
  1041
jaroslav@1890
  1042
        /**
jaroslav@1890
  1043
         * Performs common bookkeeping for poll and take: Replaces
jaroslav@1890
  1044
         * first element with last and sifts it down.  Call only when
jaroslav@1890
  1045
         * holding lock.
jaroslav@1890
  1046
         * @param f the task to remove and return
jaroslav@1890
  1047
         */
jaroslav@1890
  1048
        private RunnableScheduledFuture finishPoll(RunnableScheduledFuture f) {
jaroslav@1890
  1049
            int s = --size;
jaroslav@1890
  1050
            RunnableScheduledFuture x = queue[s];
jaroslav@1890
  1051
            queue[s] = null;
jaroslav@1890
  1052
            if (s != 0)
jaroslav@1890
  1053
                siftDown(0, x);
jaroslav@1890
  1054
            setIndex(f, -1);
jaroslav@1890
  1055
            return f;
jaroslav@1890
  1056
        }
jaroslav@1890
  1057
jaroslav@1890
  1058
        public RunnableScheduledFuture poll() {
jaroslav@1890
  1059
            final ReentrantLock lock = this.lock;
jaroslav@1890
  1060
            lock.lock();
jaroslav@1890
  1061
            try {
jaroslav@1890
  1062
                RunnableScheduledFuture first = queue[0];
jaroslav@1890
  1063
                if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
jaroslav@1890
  1064
                    return null;
jaroslav@1890
  1065
                else
jaroslav@1890
  1066
                    return finishPoll(first);
jaroslav@1890
  1067
            } finally {
jaroslav@1890
  1068
                lock.unlock();
jaroslav@1890
  1069
            }
jaroslav@1890
  1070
        }
jaroslav@1890
  1071
jaroslav@1890
  1072
        public RunnableScheduledFuture take() throws InterruptedException {
jaroslav@1890
  1073
            final ReentrantLock lock = this.lock;
jaroslav@1890
  1074
            lock.lockInterruptibly();
jaroslav@1890
  1075
            try {
jaroslav@1890
  1076
                for (;;) {
jaroslav@1890
  1077
                    RunnableScheduledFuture first = queue[0];
jaroslav@1890
  1078
                    if (first == null)
jaroslav@1890
  1079
                        available.await();
jaroslav@1890
  1080
                    else {
jaroslav@1890
  1081
                        long delay = first.getDelay(TimeUnit.NANOSECONDS);
jaroslav@1890
  1082
                        if (delay <= 0)
jaroslav@1890
  1083
                            return finishPoll(first);
jaroslav@1890
  1084
                        else if (leader != null)
jaroslav@1890
  1085
                            available.await();
jaroslav@1890
  1086
                        else {
jaroslav@1890
  1087
                            Thread thisThread = Thread.currentThread();
jaroslav@1890
  1088
                            leader = thisThread;
jaroslav@1890
  1089
                            try {
jaroslav@1890
  1090
                                available.awaitNanos(delay);
jaroslav@1890
  1091
                            } finally {
jaroslav@1890
  1092
                                if (leader == thisThread)
jaroslav@1890
  1093
                                    leader = null;
jaroslav@1890
  1094
                            }
jaroslav@1890
  1095
                        }
jaroslav@1890
  1096
                    }
jaroslav@1890
  1097
                }
jaroslav@1890
  1098
            } finally {
jaroslav@1890
  1099
                if (leader == null && queue[0] != null)
jaroslav@1890
  1100
                    available.signal();
jaroslav@1890
  1101
                lock.unlock();
jaroslav@1890
  1102
            }
jaroslav@1890
  1103
        }
jaroslav@1890
  1104
jaroslav@1890
  1105
        public RunnableScheduledFuture poll(long timeout, TimeUnit unit)
jaroslav@1890
  1106
            throws InterruptedException {
jaroslav@1890
  1107
            long nanos = unit.toNanos(timeout);
jaroslav@1890
  1108
            final ReentrantLock lock = this.lock;
jaroslav@1890
  1109
            lock.lockInterruptibly();
jaroslav@1890
  1110
            try {
jaroslav@1890
  1111
                for (;;) {
jaroslav@1890
  1112
                    RunnableScheduledFuture first = queue[0];
jaroslav@1890
  1113
                    if (first == null) {
jaroslav@1890
  1114
                        if (nanos <= 0)
jaroslav@1890
  1115
                            return null;
jaroslav@1890
  1116
                        else
jaroslav@1890
  1117
                            nanos = available.awaitNanos(nanos);
jaroslav@1890
  1118
                    } else {
jaroslav@1890
  1119
                        long delay = first.getDelay(TimeUnit.NANOSECONDS);
jaroslav@1890
  1120
                        if (delay <= 0)
jaroslav@1890
  1121
                            return finishPoll(first);
jaroslav@1890
  1122
                        if (nanos <= 0)
jaroslav@1890
  1123
                            return null;
jaroslav@1890
  1124
                        if (nanos < delay || leader != null)
jaroslav@1890
  1125
                            nanos = available.awaitNanos(nanos);
jaroslav@1890
  1126
                        else {
jaroslav@1890
  1127
                            Thread thisThread = Thread.currentThread();
jaroslav@1890
  1128
                            leader = thisThread;
jaroslav@1890
  1129
                            try {
jaroslav@1890
  1130
                                long timeLeft = available.awaitNanos(delay);
jaroslav@1890
  1131
                                nanos -= delay - timeLeft;
jaroslav@1890
  1132
                            } finally {
jaroslav@1890
  1133
                                if (leader == thisThread)
jaroslav@1890
  1134
                                    leader = null;
jaroslav@1890
  1135
                            }
jaroslav@1890
  1136
                        }
jaroslav@1890
  1137
                    }
jaroslav@1890
  1138
                }
jaroslav@1890
  1139
            } finally {
jaroslav@1890
  1140
                if (leader == null && queue[0] != null)
jaroslav@1890
  1141
                    available.signal();
jaroslav@1890
  1142
                lock.unlock();
jaroslav@1890
  1143
            }
jaroslav@1890
  1144
        }
jaroslav@1890
  1145
jaroslav@1890
  1146
        public void clear() {
jaroslav@1890
  1147
            final ReentrantLock lock = this.lock;
jaroslav@1890
  1148
            lock.lock();
jaroslav@1890
  1149
            try {
jaroslav@1890
  1150
                for (int i = 0; i < size; i++) {
jaroslav@1890
  1151
                    RunnableScheduledFuture t = queue[i];
jaroslav@1890
  1152
                    if (t != null) {
jaroslav@1890
  1153
                        queue[i] = null;
jaroslav@1890
  1154
                        setIndex(t, -1);
jaroslav@1890
  1155
                    }
jaroslav@1890
  1156
                }
jaroslav@1890
  1157
                size = 0;
jaroslav@1890
  1158
            } finally {
jaroslav@1890
  1159
                lock.unlock();
jaroslav@1890
  1160
            }
jaroslav@1890
  1161
        }
jaroslav@1890
  1162
jaroslav@1890
  1163
        /**
jaroslav@1890
  1164
         * Return and remove first element only if it is expired.
jaroslav@1890
  1165
         * Used only by drainTo.  Call only when holding lock.
jaroslav@1890
  1166
         */
jaroslav@1890
  1167
        private RunnableScheduledFuture pollExpired() {
jaroslav@1890
  1168
            RunnableScheduledFuture first = queue[0];
jaroslav@1890
  1169
            if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
jaroslav@1890
  1170
                return null;
jaroslav@1890
  1171
            return finishPoll(first);
jaroslav@1890
  1172
        }
jaroslav@1890
  1173
jaroslav@1890
  1174
        public int drainTo(Collection<? super Runnable> c) {
jaroslav@1890
  1175
            if (c == null)
jaroslav@1890
  1176
                throw new NullPointerException();
jaroslav@1890
  1177
            if (c == this)
jaroslav@1890
  1178
                throw new IllegalArgumentException();
jaroslav@1890
  1179
            final ReentrantLock lock = this.lock;
jaroslav@1890
  1180
            lock.lock();
jaroslav@1890
  1181
            try {
jaroslav@1890
  1182
                RunnableScheduledFuture first;
jaroslav@1890
  1183
                int n = 0;
jaroslav@1890
  1184
                while ((first = pollExpired()) != null) {
jaroslav@1890
  1185
                    c.add(first);
jaroslav@1890
  1186
                    ++n;
jaroslav@1890
  1187
                }
jaroslav@1890
  1188
                return n;
jaroslav@1890
  1189
            } finally {
jaroslav@1890
  1190
                lock.unlock();
jaroslav@1890
  1191
            }
jaroslav@1890
  1192
        }
jaroslav@1890
  1193
jaroslav@1890
  1194
        public int drainTo(Collection<? super Runnable> c, int maxElements) {
jaroslav@1890
  1195
            if (c == null)
jaroslav@1890
  1196
                throw new NullPointerException();
jaroslav@1890
  1197
            if (c == this)
jaroslav@1890
  1198
                throw new IllegalArgumentException();
jaroslav@1890
  1199
            if (maxElements <= 0)
jaroslav@1890
  1200
                return 0;
jaroslav@1890
  1201
            final ReentrantLock lock = this.lock;
jaroslav@1890
  1202
            lock.lock();
jaroslav@1890
  1203
            try {
jaroslav@1890
  1204
                RunnableScheduledFuture first;
jaroslav@1890
  1205
                int n = 0;
jaroslav@1890
  1206
                while (n < maxElements && (first = pollExpired()) != null) {
jaroslav@1890
  1207
                    c.add(first);
jaroslav@1890
  1208
                    ++n;
jaroslav@1890
  1209
                }
jaroslav@1890
  1210
                return n;
jaroslav@1890
  1211
            } finally {
jaroslav@1890
  1212
                lock.unlock();
jaroslav@1890
  1213
            }
jaroslav@1890
  1214
        }
jaroslav@1890
  1215
jaroslav@1890
  1216
        public Object[] toArray() {
jaroslav@1890
  1217
            final ReentrantLock lock = this.lock;
jaroslav@1890
  1218
            lock.lock();
jaroslav@1890
  1219
            try {
jaroslav@1890
  1220
                return Arrays.copyOf(queue, size, Object[].class);
jaroslav@1890
  1221
            } finally {
jaroslav@1890
  1222
                lock.unlock();
jaroslav@1890
  1223
            }
jaroslav@1890
  1224
        }
jaroslav@1890
  1225
jaroslav@1890
  1226
        @SuppressWarnings("unchecked")
jaroslav@1890
  1227
        public <T> T[] toArray(T[] a) {
jaroslav@1890
  1228
            final ReentrantLock lock = this.lock;
jaroslav@1890
  1229
            lock.lock();
jaroslav@1890
  1230
            try {
jaroslav@1890
  1231
                if (a.length < size)
jaroslav@1890
  1232
                    return (T[]) Arrays.copyOf(queue, size, a.getClass());
jaroslav@1890
  1233
                System.arraycopy(queue, 0, a, 0, size);
jaroslav@1890
  1234
                if (a.length > size)
jaroslav@1890
  1235
                    a[size] = null;
jaroslav@1890
  1236
                return a;
jaroslav@1890
  1237
            } finally {
jaroslav@1890
  1238
                lock.unlock();
jaroslav@1890
  1239
            }
jaroslav@1890
  1240
        }
jaroslav@1890
  1241
jaroslav@1890
  1242
        public Iterator<Runnable> iterator() {
jaroslav@1890
  1243
            return new Itr(Arrays.copyOf(queue, size));
jaroslav@1890
  1244
        }
jaroslav@1890
  1245
jaroslav@1890
  1246
        /**
jaroslav@1890
  1247
         * Snapshot iterator that works off copy of underlying q array.
jaroslav@1890
  1248
         */
jaroslav@1890
  1249
        private class Itr implements Iterator<Runnable> {
jaroslav@1890
  1250
            final RunnableScheduledFuture[] array;
jaroslav@1890
  1251
            int cursor = 0;     // index of next element to return
jaroslav@1890
  1252
            int lastRet = -1;   // index of last element, or -1 if no such
jaroslav@1890
  1253
jaroslav@1890
  1254
            Itr(RunnableScheduledFuture[] array) {
jaroslav@1890
  1255
                this.array = array;
jaroslav@1890
  1256
            }
jaroslav@1890
  1257
jaroslav@1890
  1258
            public boolean hasNext() {
jaroslav@1890
  1259
                return cursor < array.length;
jaroslav@1890
  1260
            }
jaroslav@1890
  1261
jaroslav@1890
  1262
            public Runnable next() {
jaroslav@1890
  1263
                if (cursor >= array.length)
jaroslav@1890
  1264
                    throw new NoSuchElementException();
jaroslav@1890
  1265
                lastRet = cursor;
jaroslav@1890
  1266
                return array[cursor++];
jaroslav@1890
  1267
            }
jaroslav@1890
  1268
jaroslav@1890
  1269
            public void remove() {
jaroslav@1890
  1270
                if (lastRet < 0)
jaroslav@1890
  1271
                    throw new IllegalStateException();
jaroslav@1890
  1272
                DelayedWorkQueue.this.remove(array[lastRet]);
jaroslav@1890
  1273
                lastRet = -1;
jaroslav@1890
  1274
            }
jaroslav@1890
  1275
        }
jaroslav@1890
  1276
    }
jaroslav@1890
  1277
}