io.netty.util.concurrent.ScheduledFutureTask Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.util.concurrent;
import io.netty.util.internal.DefaultPriorityQueue;
import io.netty.util.internal.PriorityQueueNode;
import java.util.concurrent.Callable;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("ComparableImplementedButEqualsNotOverridden")
final class ScheduledFutureTask extends PromiseTask implements ScheduledFuture, PriorityQueueNode {
private static final long START_TIME = System.nanoTime();
static long nanoTime() {
return System.nanoTime() - START_TIME;
}
static long deadlineNanos(long delay) {
long deadlineNanos = nanoTime() + delay;
// Guard against overflow
return deadlineNanos < 0 ? Long.MAX_VALUE : deadlineNanos;
}
static long initialNanoTime() {
return START_TIME;
}
// set once when added to priority queue
private long id;
private long deadlineNanos;
/* 0 - no repeat, >0 - repeat at fixed rate, <0 - repeat with fixed delay */
private final long periodNanos;
private int queueIndex = INDEX_NOT_IN_QUEUE;
ScheduledFutureTask(AbstractScheduledEventExecutor executor,
Runnable runnable, long nanoTime) {
super(executor, runnable);
deadlineNanos = nanoTime;
periodNanos = 0;
}
ScheduledFutureTask(AbstractScheduledEventExecutor executor,
Runnable runnable, long nanoTime, long period) {
super(executor, runnable);
deadlineNanos = nanoTime;
periodNanos = validatePeriod(period);
}
ScheduledFutureTask(AbstractScheduledEventExecutor executor,
Callable callable, long nanoTime, long period) {
super(executor, callable);
deadlineNanos = nanoTime;
periodNanos = validatePeriod(period);
}
ScheduledFutureTask(AbstractScheduledEventExecutor executor,
Callable callable, long nanoTime) {
super(executor, callable);
deadlineNanos = nanoTime;
periodNanos = 0;
}
private static long validatePeriod(long period) {
if (period == 0) {
throw new IllegalArgumentException("period: 0 (expected: != 0)");
}
return period;
}
ScheduledFutureTask setId(long id) {
if (this.id == 0L) {
this.id = id;
}
return this;
}
@Override
protected EventExecutor executor() {
return super.executor();
}
public long deadlineNanos() {
return deadlineNanos;
}
void setConsumed() {
// Optimization to avoid checking system clock again
// after deadline has passed and task has been dequeued
if (periodNanos == 0) {
assert nanoTime() >= deadlineNanos;
deadlineNanos = 0L;
}
}
public long delayNanos() {
return deadlineToDelayNanos(deadlineNanos());
}
static long deadlineToDelayNanos(long deadlineNanos) {
return deadlineNanos == 0L ? 0L : Math.max(0L, deadlineNanos - nanoTime());
}
public long delayNanos(long currentTimeNanos) {
return deadlineNanos == 0L ? 0L
: Math.max(0L, deadlineNanos() - (currentTimeNanos - START_TIME));
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(delayNanos(), TimeUnit.NANOSECONDS);
}
@Override
public int compareTo(Delayed o) {
if (this == o) {
return 0;
}
ScheduledFutureTask> that = (ScheduledFutureTask>) o;
long d = deadlineNanos() - that.deadlineNanos();
if (d < 0) {
return -1;
} else if (d > 0) {
return 1;
} else if (id < that.id) {
return -1;
} else {
assert id != that.id;
return 1;
}
}
@Override
public void run() {
assert executor().inEventLoop();
try {
if (delayNanos() > 0L) {
// Not yet expired, need to add or remove from queue
if (isCancelled()) {
scheduledExecutor().scheduledTaskQueue().removeTyped(this);
} else {
scheduledExecutor().scheduleFromEventLoop(this);
}
return;
}
if (periodNanos == 0) {
if (setUncancellableInternal()) {
V result = runTask();
setSuccessInternal(result);
}
} else {
// check if is done as it may was cancelled
if (!isCancelled()) {
runTask();
if (!executor().isShutdown()) {
if (periodNanos > 0) {
deadlineNanos += periodNanos;
} else {
deadlineNanos = nanoTime() - periodNanos;
}
if (!isCancelled()) {
scheduledExecutor().scheduledTaskQueue().add(this);
}
}
}
}
} catch (Throwable cause) {
setFailureInternal(cause);
}
}
private AbstractScheduledEventExecutor scheduledExecutor() {
return (AbstractScheduledEventExecutor) executor();
}
/**
* {@inheritDoc}
*
* @param mayInterruptIfRunning this value has no effect in this implementation.
*/
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
boolean canceled = super.cancel(mayInterruptIfRunning);
if (canceled) {
scheduledExecutor().removeScheduled(this);
}
return canceled;
}
boolean cancelWithoutRemove(boolean mayInterruptIfRunning) {
return super.cancel(mayInterruptIfRunning);
}
@Override
protected StringBuilder toStringBuilder() {
StringBuilder buf = super.toStringBuilder();
buf.setCharAt(buf.length() - 1, ',');
return buf.append(" deadline: ")
.append(deadlineNanos)
.append(", period: ")
.append(periodNanos)
.append(')');
}
@Override
public int priorityQueueIndex(DefaultPriorityQueue> queue) {
return queueIndex;
}
@Override
public void priorityQueueIndex(DefaultPriorityQueue> queue, int i) {
queueIndex = i;
}
}