时间轮算法

 

一、原理:

可以将 HashedWheelTimer 看做一个时钟,有12个数字(1~12),每个时间点对应一个桶,桶里装着任务的列表,每间隔一个时间单位(tickDuration),指针跳到下一个时间点,然后遍历桶里的任务,如果任务到了执行时间,就执行。结构如下图:

二、源码

1.属性

/**
 * HashedWheelTimer的注释特别说明了不要创建多个HashedWheelTimer对象, HashedWheelTimer是用来管理大量的定时任务的,
 * 但这些任务要放在同一个Timer对象里面管理
 */
public static final String NAME = "hased";

private static final Logger logger = LoggerFactory.getLogger(HashedWheelTimer.class);
// HashedWheelTimer对象个数
private static final AtomicInteger INSTANCE_COUNTER = new AtomicInteger();
private static final AtomicBoolean WARNED_TOO_MANY_INSTANCES = new AtomicBoolean();
private static final int INSTANCE_COUNT_LIMIT = 64;
// 采用cas的方式更新定时任务状态 AtomicIntegerFieldUpdater是JUC里面的类,
// 原理是利用安全的反射进行原子操作,来获取实例的本身的属性。有比AtomicInteger更好的性能和更低得内存占用。
private static final AtomicIntegerFieldUpdater<HashedWheelTimer> WORKER_STATE_UPDATER =
		AtomicIntegerFieldUpdater.newUpdater(HashedWheelTimer.class, "workerState");
// 任务执行与调度者
private final Worker worker = new Worker();
// 执行任务与调度者线程
private final Thread workerThread;
//定时任务的三种状态
private static final int WORKER_STATE_INIT = 0;
private static final int WORKER_STATE_STARTED = 1;
private static final int WORKER_STATE_SHUTDOWN = 2;

/**
 * 0 - init, 1 - started, 2 - shut down
 */
@SuppressWarnings({"unused", "FieldMayBeFinal"})
private volatile int workerState;
// 间隔多久走到下一槽(相当于时钟走一格)
private final long tickDuration;
// 对应每个槽(2^n)
private final HashedWheelBucket[] wheel;
// 槽数 - 1 (用来快速取模)
private final int mask;
private final CountDownLatch startTimeInitialized = new CountDownLatch(1);
// 存放任务列表,加入任务时,先存入阻塞队列,指针每跳动一次,都会从该队列中取出最多10w个,放入对应的每个槽中
private final Queue<HashedWheelTimeout> timeouts = new ArrayBlockingQueue<HashedWheelTimeout>(1024);
// 取消任务队列
private final Queue<HashedWheelTimeout> cancelledTimeouts = new ArrayBlockingQueue<HashedWheelTimeout>(1024);
// 当前运行任务个数
private final AtomicLong pendingTimeouts = new AtomicLong(0);
// 运行期间最大运行任务个数(大于0生效)
private final long maxPendingTimeouts;
// 任务开始时的时间,计算每个槽对应的位置,都是通过(任务执行时间 -开始时间) % mask
private volatile long startTime;

2.主要构造方法

/**
 * Creates a new timer.
 *
 * @param threadFactory      a {@link ThreadFactory} that creates a
 *                           background {@link Thread} which is dedicated to
 *                           {@link TimerTask} execution.
 * @param tickDuration       the duration between tick
 * @param unit               the time unit of the {@code tickDuration}
 * @param ticksPerWheel      the size of the wheel
 * @param maxPendingTimeouts The maximum number of pending timeouts after which call to
 *                           {@code newTimeout} will result in
 *                           {@link java.util.concurrent.RejectedExecutionException}
 *                           being thrown. No maximum pending timeouts limit is assumed if
 *                           this value is 0 or negative.
 * @throws NullPointerException     if either of {@code threadFactory} and {@code unit} is {@code null}
 * @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is &lt;= 0
 */
public HashedWheelTimer(
		ThreadFactory threadFactory,// 用来创建worker线程
		long tickDuration,// tick的时长,也就是指针多久转一格
		TimeUnit unit,// tickDuration的时间单位
		int ticksPerWheel,// 一圈有几格
		long maxPendingTimeouts// 是否开启内存泄露检测
) {
	// 参数校验
	if (threadFactory == null) {
		throw new NullPointerException("threadFactory");
	}
	if (unit == null) {
		throw new NullPointerException("unit");
	}
	if (tickDuration <= 0) {
		throw new IllegalArgumentException("tickDuration must be greater than 0: " + tickDuration);
	}
	if (ticksPerWheel <= 0) {
		throw new IllegalArgumentException("ticksPerWheel must be greater than 0: " + ticksPerWheel);
	}

	// Normalize ticksPerWheel to power of two and initialize the wheel.
	//创建时间轮的基本数据结构 一个数组 长度会自动转换为2的N次方
	// 一般如果我们hash取模定位的话,用%,但这个没有二进制运算高效
	wheel = createWheel(ticksPerWheel);
	//用来快速计算我们的任务应该处于时间槽哪一个位置  也就是进行&操作
	mask = wheel.length - 1;

	// Convert tickDuration to nanos.时间转换成纳秒
	this.tickDuration = unit.toNanos(tickDuration);

	// Prevent overflow.
	// 校验是否存在溢出。即指针转动的时间间隔不能太长而导致
	// tickDuration * wheel.length > Long.MAX_VALUE
	if (this.tickDuration >= Long.MAX_VALUE / wheel.length) {
		throw new IllegalArgumentException(String.format(
				"tickDuration: %d (expected: 0 < tickDuration in nanos < %d",
				tickDuration, Long.MAX_VALUE / wheel.length));
	}
	//创建work线程
	workerThread = threadFactory.newThread(worker);
	//任务的超时等待时间如果有设置超时 那么超时之后就会抛异常
	this.maxPendingTimeouts = maxPendingTimeouts;
	//这玩意比较耗资源,所以会控制实例化数目
	// 当HashedWheelTimer实例超过当前cpu可用核数最大的实例数为64个,也就是一个jvm最多只能有64个
	// 时间轮对象实例,因为时间轮是一个非常耗费资源的结构所以实例数目不能太高
	if (INSTANCE_COUNTER.incrementAndGet() > INSTANCE_COUNT_LIMIT &&
			WARNED_TOO_MANY_INSTANCES.compareAndSet(false, true)) {
		reportTooManyInstances();
	}
}
//计算槽位个数
private static int normalizeTicksPerWheel(int ticksPerWheel) {
	int normalizedTicksPerWheel = 1;
	//所以最终结果一定是2的n次方
	while (normalizedTicksPerWheel < ticksPerWheel) {
		normalizedTicksPerWheel <<= 1;
	}
	return normalizedTicksPerWheel;
}
//创建槽位
private static HashedWheelBucket[] createWheel(int ticksPerWheel) {
	if (ticksPerWheel <= 0) {
		throw new IllegalArgumentException(
				"ticksPerWheel must be greater than 0: " + ticksPerWheel);
	}
	if (ticksPerWheel > 1073741824) {
		throw new IllegalArgumentException(
				"ticksPerWheel may not be greater than 2^30: " + ticksPerWheel);
	}
	// 计算槽位个数 result = 2^n > ticksPerWheel
	ticksPerWheel = normalizeTicksPerWheel(ticksPerWheel);
	HashedWheelBucket[] wheel = new HashedWheelBucket[ticksPerWheel];
	for (int i = 0; i < wheel.length; i++) {
		wheel[i] = new HashedWheelBucket();
	}
	return wheel;
}

3.start方法

/**
 * Starts the background thread explicitly.  The background thread will
 * start automatically on demand even if you did not call this method.
 *
 * @throws IllegalStateException if this timer has been
 *                               {@linkplain #stop() stopped} already
 */
//不需要你主动调用,当有任务添加进来的的时候他就会跑
public void start() {
	// 判断当前时间轮的状态,如果是初始化,则启动worker线程,启动整个时间轮;
	// 如果已经启动则略过;如果是已经停止,则报错
	// 这里是一个Lock Free的设计。因为可能有多个线程调用启动方法,
	// 这里使用AtomicIntegerFieldUpdater原子的更新时间轮的状态
	//因此使用这个方法来获取实例的允许状态,防止重入
	switch (WORKER_STATE_UPDATER.get(this)) {
		case WORKER_STATE_INIT:
			//cas锁 保证只有一个能够启动
			if (WORKER_STATE_UPDATER.compareAndSet(this, WORKER_STATE_INIT, WORKER_STATE_STARTED)) {
				workerThread.start();
			}
			break;
		case WORKER_STATE_STARTED:
			break;
		case WORKER_STATE_SHUTDOWN:
			throw new IllegalStateException("cannot be started once stopped");
		default:
			throw new Error("Invalid WorkerState");
	}

	// Wait until the startTime is initialized by the worker.
	//等待work线程初始化时间轮的启动时间
	while (startTime == 0) {
		try {
			//这里使用countDownLauch来确保调度的线程已经被启动
			startTimeInitialized.await();
		} catch (InterruptedException ignore) {
			// Ignore - it will be ready very soon.
		}
	}
}

4.stop方法

@Override
public Set<Timeout> stop() {
	// worker线程不能停止时间轮,也就是加入的定时任务,不能调用这个方法。
	// 不然会有恶意的定时任务调用这个方法而造成大量定时任务失效
	if (Thread.currentThread() == workerThread) {
		throw new IllegalStateException(
				HashedWheelTimer.class.getSimpleName() +
						".stop() cannot be called from " +
						TimerTask.class.getSimpleName());
	}
	// 尝试CAS替换当前状态为“停止:2”。如果失败,则当前时间轮的状态只能是“初始化:0”或者“停止:2”。
	//直接将当前状态设置为“停止:2“
	if (!WORKER_STATE_UPDATER.compareAndSet(this, WORKER_STATE_STARTED, WORKER_STATE_SHUTDOWN)) {
		// workerState can be 0 or 2 at this moment - let it always be 2.
		if (WORKER_STATE_UPDATER.getAndSet(this, WORKER_STATE_SHUTDOWN) != WORKER_STATE_SHUTDOWN) {
			INSTANCE_COUNTER.decrementAndGet();
		}

		return Collections.emptySet();
	}

	try {
		// 终端worker线程,尝试把正在进行任务的线程中断掉,如果某些任务正在执行则会,
	   //抛出interrupt异常,并且任务会尝试立即中断
		boolean interrupted = false;
		while (workerThread.isAlive()) {
			workerThread.interrupt();
			try {
				//当前前程会等待stop的结果
				workerThread.join(100);
			} catch (InterruptedException ignored) {
				interrupted = true;
			}
		}

		// 从中断中恢复

		if (interrupted) {
			// 如果中断掉了所有工作的线程,那么当前关闭时间轮调度的线程会在随后关闭
			Thread.currentThread().interrupt();
		}
	} finally {
		INSTANCE_COUNTER.decrementAndGet();
	}
	//返回未处理的任务
	return worker.unprocessedTimeouts();
}

5.newTimeout方法

//添加定时任务
@Override
public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {
	if (task == null) {
		throw new NullPointerException("task");
	}
	if (unit == null) {
		throw new NullPointerException("unit");
	}

	long pendingTimeoutsCount = pendingTimeouts.incrementAndGet();

	if (maxPendingTimeouts > 0 && pendingTimeoutsCount > maxPendingTimeouts) {
		pendingTimeouts.decrementAndGet();
		throw new RejectedExecutionException("Number of pending timeouts ("
				+ pendingTimeoutsCount + ") is greater than or equal to maximum allowed pending "
				+ "timeouts (" + maxPendingTimeouts + ")");
	}
	//如果没有启动,则启动
	start();

	// Add the timeout to the timeout queue which will be processed on the next tick.
	// During processing all the queued HashedWheelTimeouts will be added to the correct HashedWheelBucket.
	// 计算任务的deadline
	long deadline = System.nanoTime() + unit.toNanos(delay) - startTime;

	// Guard against overflow.
	if (delay > 0 && deadline < 0) {
		deadline = Long.MAX_VALUE;
	}
	 这里定时任务不是直接加到对应的格子中,而是先加入到一个队列里,
	// 然后等到下一个tick的时候,会从队列里取出最多100000个任务加入到指定的格子中
	HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline);
	timeouts.add(timeout);
	return timeout;
}

6.Worker 内部类

该类是时间论算法的核心类,主要处理逻辑,都在该类中。

private final class Worker implements Runnable {
	private final Set<Timeout> unprocessedTimeouts = new HashSet<Timeout>();

	private long tick;

	@Override
	public void run() {
		// Initialize the startTime.
		// 初始化startTime.只有所有任务的的deadline都是想对于这个时间点
		startTime = System.nanoTime();
		// 由于System.nanoTime()可能返回0,甚至负数。并且0是一个标示符,用来判断startTime是否被初始化,
		// 所以当startTime=0的时候,重新赋值为1
		if (startTime == 0) {
			// We use 0 as an indicator for the uninitialized value here, so make sure it's not 0 when initialized.
			startTime = 1;
		}

		// Notify the other threads waiting for the initialization at start().
		//唤醒阻塞在start的线程
		startTimeInitialized.countDown();

		do {
			// 计算需要sleep的时间
			final long deadline = waitForNextTick();
			if (deadline > 0) {
				int idx = (int) (tick & mask);
				processCancelledTasks();
				HashedWheelBucket bucket =
						wheel[idx];
				transferTimeoutsToBuckets();
				bucket.expireTimeouts(deadline);
				tick++;
			}
		} while (WORKER_STATE_UPDATER.get(HashedWheelTimer.this) == WORKER_STATE_STARTED);

		// Fill the unprocessedTimeouts so we can return them from stop() method.
		//填充未处理的超时
		for (HashedWheelBucket bucket : wheel) {
			bucket.clearTimeouts(unprocessedTimeouts);
		}
		for (; ; ) {
			HashedWheelTimeout timeout = timeouts.poll();
			if (timeout == null) {
				break;
			}
			if (!timeout.isCancelled()) {
				unprocessedTimeouts.add(timeout);
			}
		}
		processCancelledTasks();
	}
	// 将newTimeout()方法中加入到待处理定时任务队列中的任务加入到指定的格子中
	private void transferTimeoutsToBuckets() {
		// transfer only max. 100000 timeouts per tick to prevent a thread to stale the workerThread when it just
		// adds new timeouts in a loop.
		// 每次tick只处理10w个任务,以免阻塞worker线程
		for (int i = 0; i < 100000; i++) {
			HashedWheelTimeout timeout = timeouts.poll();
			if (timeout == null) {
				// all processed
				break;
			}
			//已经被取消了;
			if (timeout.state() == HashedWheelTimeout.ST_CANCELLED) {
				// Was cancelled in the meantime.
				continue;
			}
			// 计算任务需要经过多少个tick
			long calculated = timeout.deadline / tickDuration;
			// 计算任务的轮数
			timeout.remainingRounds = (calculated - tick) / wheel.length;

			// Ensure we don't schedule for past.
			//如果任务在timeouts队列里面放久了, 以至于已经过了执行时间, 这个时候就使用当前tick, 也就是放到当前bucket, 此方法调用完后就会被执行.
			final long ticks = Math.max(calculated, tick);
			int stopIndex = (int) (ticks & mask);
			// 将任务加入到响应的格子中
			HashedWheelBucket bucket = wheel[stopIndex];
			bucket.addTimeout(timeout);
		}
	}
	// 将取消的任务取出,并从格子中移除
	private void processCancelledTasks() {
		for (; ; ) {
			HashedWheelTimeout timeout = cancelledTimeouts.poll();
			if (timeout == null) {
				// all processed
				break;
			}
			try {
				timeout.remove();
			} catch (Throwable t) {
				if (logger.isWarnEnabled()) {
					logger.warn("An exception was thrown while process a cancellation task", t);
				}
			}
		}
	}

	/**
	 * calculate goal nanoTime from startTime and current tick number,
	 * then wait until that goal has been reached.
	 *
	 * @return Long.MIN_VALUE if received a shutdown request,
	 * current time otherwise (with Long.MIN_VALUE changed by +1)
	 */
	//sleep, 直到下次tick到来, 然后返回该次tick和启动时间之间的时长
	private long waitForNextTick() {
		long deadline = tickDuration * (tick + 1);

		for (; ; ) {
			// 计算需要sleep的时间, 之所以加999999后再除10000000,前面是1所以这里需要减去1,
			// 才能计算准确,还有通过这里可以看到,
			//其实线程是以睡眠一定的时候再来执行下一个ticket的任务的,
			//这样如果ticket的间隔设置的太小的话,系统会频繁的睡眠然后启动,
			//其实感觉影响部分的性能,所以为了更好的利用系统资源步长可以稍微设置大点
			final long currentTime = System.nanoTime() - startTime;
			long sleepTimeMs = (deadline - currentTime + 999999) / 1000000;

			if (sleepTimeMs <= 0) {
				if (currentTime == Long.MIN_VALUE) {
					return -Long.MAX_VALUE;
				} else {
					return currentTime;
				}
			}
			if (isWindows()) {
				// 这里是因为windows平台的定时调度最小单位为10ms,
				// 如果不是10ms的倍数,可能会引起sleep时间不准确
				sleepTimeMs = sleepTimeMs / 10 * 10;
			}

			try {
				Thread.sleep(sleepTimeMs);
			} catch (InterruptedException ignored) {
				// 调用HashedWheelTimer.stop()时优雅退出
				if (WORKER_STATE_UPDATER.get(HashedWheelTimer.this) == WORKER_STATE_SHUTDOWN) {
					return Long.MIN_VALUE;
				}
			}
		}
	}

	Set<Timeout> unprocessedTimeouts() {
		return Collections.unmodifiableSet(unprocessedTimeouts);
	}
}

7.HashedWheelTimeout 内部类

定时任务的内部包装类,双向链表结构。会保存定时任务到期执行的任务、deadline、round等信息。

private static final class HashedWheelTimeout implements Timeout {

	private static final int ST_INIT = 0;
	private static final int ST_CANCELLED = 1;
	private static final int ST_EXPIRED = 2;
	// 用来CAS方式更新定时任务状态
	private static final AtomicIntegerFieldUpdater<HashedWheelTimeout> STATE_UPDATER =
			AtomicIntegerFieldUpdater.newUpdater(HashedWheelTimeout.class, "state");

	private final HashedWheelTimer timer;
	//具体到期要执行的任务
	private final TimerTask task;
	private final long deadline;

	@SuppressWarnings({"unused", "FieldMayBeFinal", "RedundantFieldInitialization"})
	private volatile int state = ST_INIT;

	/**
	 * RemainingRounds will be calculated and set by Worker.transferTimeoutsToBuckets() before the
	 * HashedWheelTimeout will be added to the correct HashedWheelBucket.
	 */
	//离任务执行的轮数 任务加入后是计算这个值,每过一轮,该值-1
	long remainingRounds;

	/**
	 * This will be used to chain timeouts in HashedWheelTimerBucket via a double-linked-list.
	 * As only the workerThread will act on it there is no need for synchronization / volatile.
	 */
	// 双向链表结构,由于只有worker线程会访问,这里不需要synchronization / volatile
	HashedWheelTimeout next;
	HashedWheelTimeout prev;

	/**
	 * The bucket to which the timeout was added
	 */
	//定时任务所在的槽
	HashedWheelBucket bucket;

	HashedWheelTimeout(HashedWheelTimer timer, TimerTask task, long deadline) {
		this.timer = timer;
		this.task = task;
		this.deadline = deadline;
	}

	@Override
	public Timer timer() {
		return timer;
	}

	@Override
	public TimerTask task() {
		return task;
	}

	@Override
	public boolean cancel() {
		// only update the state it will be removed from HashedWheelBucket on next tick.
		//这里只是修改状态为取消,实际会在下次tick的时候移除
		if (!compareAndSetState(ST_INIT, ST_CANCELLED)) {
			return false;
		}
		// If a task should be canceled we put this to another queue which will be processed on each tick.
		// So this means that we will have a GC latency of max. 1 tick duration which is good enough. This way
		// we can make again use of our MpscLinkedQueue and so minimize the locking / overhead as much as possible.
		// 加入到时间轮的待取消队列,并在每次tick的时候,从相应格子中移除。
		timer.cancelledTimeouts.add(this);
		return true;
	}

	void remove() {
		HashedWheelBucket bucket = this.bucket;
		if (bucket != null) {
			bucket.remove(this);
		} else {
			timer.pendingTimeouts.decrementAndGet();
		}
	}

	public boolean compareAndSetState(int expected, int state) {
		return STATE_UPDATER.compareAndSet(this, expected, state);
	}

	public int state() {
		return state;
	}

	@Override
	public boolean isCancelled() {
		return state() == ST_CANCELLED;
	}

	@Override
	public boolean isExpired() {
		return state() == ST_EXPIRED;
	}
	//过期并执行任务
	public void expire() {
		if (!compareAndSetState(ST_INIT, ST_EXPIRED)) {
			return;
		}

		try {
			task.run(this);
		} catch (Throwable t) {
			if (logger.isWarnEnabled()) {
				logger.warn("An exception was thrown by " + TimerTask.class.getSimpleName() + '.', t);
			}
		}
	}

	@Override
	public String toString() {
		final long currentTime = System.nanoTime();
		long remaining = deadline - currentTime + timer.startTime;
		String simpleClassName = ClassHelper.simpleClassName(this.getClass());

		StringBuilder buf = new StringBuilder(192)
				.append(simpleClassName)
				.append('(')
				.append("deadline: ");
		if (remaining > 0) {
			buf.append(remaining)
					.append(" ns later");
		} else if (remaining < 0) {
			buf.append(-remaining)
					.append(" ns ago");
		} else {
			buf.append("now");
		}

		if (isCancelled()) {
			buf.append(", cancelled");
		}

		return buf.append(", task: ")
				.append(task())
				.append(')')
				.toString();
	}
}

8.HashedWheelBucket 内部类

/**
 * Bucket that stores HashedWheelTimeouts. These are stored in a linked-list like datastructure to allow easy
 * removal of HashedWheelTimeouts in the middle. Also the HashedWheelTimeout act as nodes themself and so no
 * extra object creation is needed.
 */
// HashedWheelBucket用来存放HashedWheelTimeout,结构类似于LinkedList。
// 提供了expireTimeouts(long deadline)方法来过期并执行格子中的定时任务
private static final class HashedWheelBucket {

	/**
	 * Used for the linked-list datastructure
	 */
	private HashedWheelTimeout head;
	private HashedWheelTimeout tail;

	/**
	 * Add {@link HashedWheelTimeout} to this bucket.
	 */
	void addTimeout(HashedWheelTimeout timeout) {
		assert timeout.bucket == null;
		timeout.bucket = this;
		if (head == null) {
			head = tail = timeout;
		} else {
			tail.next = timeout;
			timeout.prev = tail;
			tail = timeout;
		}
	}

	/**
	 * Expire all {@link HashedWheelTimeout}s for the given {@code deadline}.
	 */
	// 过期并执行格子中的到期任务,tick到该格子的时候,worker线程会调用这个方法,
	//根据deadline和remainingRounds判断任务是否过期
	void expireTimeouts(long deadline) {
		HashedWheelTimeout timeout = head;

		// process all timeouts
		//遍历格子中的所有定时任务
		while (timeout != null) {
			// 先保存next,因为移除后next将被设置为null
			HashedWheelTimeout next = timeout.next;
			if (timeout.remainingRounds <= 0) {
				next = remove(timeout);
				if (timeout.deadline <= deadline) {
					timeout.expire();
				} else {
					// The timeout was placed into a wrong slot. This should never happen.
					//不可能发生的情况,就是说round已经为0了,deadline却>当前槽的deadline
					throw new IllegalStateException(String.format(
							"timeout.deadline (%d) > deadline (%d)", timeout.deadline, deadline));
				}
			} else if (timeout.isCancelled()) {
				next = remove(timeout);
			} else {
				//没有到期。论数-1
				timeout.remainingRounds--;
			}
			timeout = next;
		}
	}

	public HashedWheelTimeout remove(HashedWheelTimeout timeout) {
		HashedWheelTimeout next = timeout.next;
		// remove timeout that was either processed or cancelled by updating the linked-list
		if (timeout.prev != null) {
			timeout.prev.next = next;
		}
		if (timeout.next != null) {
			timeout.next.prev = timeout.prev;
		}

		if (timeout == head) {
			// if timeout is also the tail we need to adjust the entry too
			if (timeout == tail) {
				tail = null;
				head = null;
			} else {
				head = next;
			}
		} else if (timeout == tail) {
			// if the timeout is the tail modify the tail to be the prev node.
			tail = timeout.prev;
		}
		// null out prev, next and bucket to allow for GC.
		timeout.prev = null;
		timeout.next = null;
		timeout.bucket = null;
		timeout.timer.pendingTimeouts.decrementAndGet();
		return next;
	}

	/**
	 * Clear this bucket and return all not expired / cancelled {@link Timeout}s.
	 */
	void clearTimeouts(Set<Timeout> set) {
		for (; ; ) {
			HashedWheelTimeout timeout = pollTimeout();
			if (timeout == null) {
				return;
			}
			if (timeout.isExpired() || timeout.isCancelled()) {
				continue;
			}
			set.add(timeout);
		}
	}

	//轮询超时
	private HashedWheelTimeout pollTimeout() {
		HashedWheelTimeout head = this.head;
		if (head == null) {
			return null;
		}
		HashedWheelTimeout next = head.next;
		if (next == null) {
			tail = this.head = null;
		} else {
			this.head = next;
			next.prev = null;
		}

		// null out prev and next to allow for GC.
		head.next = null;
		head.prev = null;
		head.bucket = null;
		return head;
	}
}

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值