All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.firefly.utils.time.HashTimeWheel Maven / Gradle / Ivy

There is a newer version: 5.0.2
Show newest version
package com.firefly.utils.time;

import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedQueue;

import com.firefly.utils.concurrent.Scheduler;

public class HashTimeWheel {
	private int maxTimers = 60; // slot's number in wheel
	private long interval = 1000; // the clock's accuracy
	
	private ConcurrentLinkedQueue[] timerSlots;
	private volatile int currentSlot = 0;
	private volatile boolean start;

	public int getMaxTimers() {
		return maxTimers;
	}

	public void setMaxTimers(int maxTimers) {
		this.maxTimers = maxTimers;
	}

	public long getInterval() {
		return interval;
	}

	public void setInterval(long interval) {
		this.interval = interval;
	}

	/**
	 * add a task
	 * 
	 * @param delay
	 *           after x milliseconds than execute runnable
	 * @param run
	 *           run task in future
	 * @return The task future
	 */
	public Future add(long delay, Runnable run) {
		final int curSlot = currentSlot;
		
		final int ticks = delay > interval ? (int) (delay / interval) : 1; // figure out how many ticks need
		final int index = (curSlot + (ticks % maxTimers)) % maxTimers; // figure out the wheel's index
		final int round = (ticks - 1) / maxTimers; // the round number of spin

		TimerTask task = new TimerTask(round, run);
		timerSlots[index].add(task);
		
		return new Future(this, index, task);
	}
	
	private final boolean remove(TimerTask task, int index) {
		return timerSlots[index].remove(task);
	}

	@SuppressWarnings("unchecked")
	public void start() {
		if (!start) {
			synchronized (this) {
				if (!start) {
					timerSlots = new ConcurrentLinkedQueue[maxTimers];
					for (int i = 0; i < timerSlots.length; i++) {
						timerSlots[i] = new ConcurrentLinkedQueue();
					}

					start = true;
					new Thread(new Worker(), "firefly time wheel").start();
				}
			}
		}
	}

	public void stop() {
		start = false;
		timerSlots = null;
	}

	private final class Worker implements Runnable {

		@Override
		public void run() {
			while (start) {
				int currentSlotTemp = currentSlot;
				ConcurrentLinkedQueue timerSlot = timerSlots[currentSlotTemp++];
				currentSlotTemp %= timerSlots.length;

				for (Iterator iterator = timerSlot.iterator(); iterator
						.hasNext();) {
					if (iterator.next().runTask())
						iterator.remove();
				}

				try {
					Thread.sleep(interval);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

				currentSlot = currentSlotTemp;
			}

		}

	}

	private final class TimerTask {
		private int round;
		private Runnable run;

		public TimerTask(int round, Runnable run) {
			this.round = round;
			this.run = run;
		}

		public boolean runTask() {
			if (round == 0) {
				run.run();
				return true;
			} else {
				round--;
				return false;
			}
		}
	}
	
	public static class Future implements Scheduler.Future {
		private HashTimeWheel timeWheel;
		private int index;
		private TimerTask task;
		
		public Future(HashTimeWheel timeWheel, int index, TimerTask task) {
			super();
			this.timeWheel = timeWheel;
			this.index = index;
			this.task = task;
		}

		/**
		 * cancel current task
		 * @return if it return true, which cancel task success, else it fail
		 */
		@Override
		public boolean cancel() {
			return timeWheel.remove(task, index);
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy