在处理大量的延迟任务的时候jdk自带的延迟定时任务队列在处理延迟任务(如删除,修改)需要logn的复杂度,这并不能满足已有
的需求,于是时间轮延迟算法被设计出来,其原理是模仿生活中的时钟,已每过一段时间,移动一格并执行该格中的任务队列,需要放置任务时,只需要放到当前格的前一格即可,待下次(走满一圈)再次走带该位置在执行此任务,此任务延迟的执行的时间就等于每格所代表的时间*总共的格数,关于时间轮算法的思想网上有很多,这里不在重复,下面给出设计思路和具体实现
1,使用定时任务,推动指针格的移动,执行当前格的任务,
2,每次添加任务时,获取当前指针格游标,将任务放在当前游标的前一格即可
下面给出具体实现
/** * Created by lin on 2018/10/2. * table数组,node节点,不可变,定时任务,移动游标 */ public interface TimeWheel { //添加到时间轮槽中的任务 void addTask(Task task); //开启时间轮 void start(); //停止时间轮 boolean stop(); }
//以下是对任务的简要抽象,因为借助了线程池调度,所需实现Runnable(或者Callable)
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** * Created by lin on 2018/10/2. */ public abstract class Task implements Runnable { /** * 0 初始状态 NEW 1 * 1 运行转态 RUNNING * 2 结束状态 END * 3 异常结束状态 * -1 取消状态,任务一旦开始就不能取消 */ public static final int NEWSTATE = 0; public static final int RUNNINGSTATE = 1; public static final int ENDSTATE = 2; public static final int EXCEPTIONSTATE = 3; public static final int CANCLESTATE = -1; private AtomicInteger taskState; public Task() { taskState = new AtomicInteger(NEWSTATE); } public boolean cancle() { int state = taskState.get(); if (state < 1) { //不需要重试 if (taskState.compareAndSet(state, -1)) { return true; } } return false; } public boolean isCanRun() { //只有处于初始转态的任务才能运行 if (getState() == 0) { return true; } return false; } public void run() { setTaskState(RUNNINGSTATE); boolean flag = true; try { taskRun(); } catch (Throwable e) { flag = false; } finally { if (flag) { setTaskState(ENDSTATE); } else { setTaskState(EXCEPTIONSTATE); } } } private void setTaskState(int state) { taskState.set(state); } public int getState() { return taskState.get(); } public abstract void taskRun(); }
//时间轮的具体实现 import java.util.*; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; /** * Created by lin on 2018/10/2. */ public class SimpleTimeWheel implements TimeWheel { //时间轮的状态,false代表关闭,true代表开启 private final AtomicBoolean state = new AtomicBoolean(false); //执行器,专门用来执行槽位中的任务 private Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); //用来推动时间轮旋转的定时任务 private Timer timer; //游标用来,指定槽位,每隔一段时间移动该槽位,并且 //会将对应槽位的任务取出进行执行 private AtomicLong current = new AtomicLong(0); private int tisksPerWheel;//数组的长度 //单位为毫秒 private int tickDuration;//每一格代表的时间长度 public static final int DEFAULT_LENGTH = 20; private volatile NodeHeader[] tasks; public SimpleTimeWheel(int tisksPerWheel, int tickDuration) { if (tisksPerWheel <= 0) { throw new IllegalArgumentException("tisksPerWheel is negative "); } if (tickDuration <= 0) { throw new IllegalArgumentException("tickDuration is negative"); } this.tisksPerWheel = tisksPerWheel; this.tickDuration = tickDuration; tasks = new NodeHeader[tisksPerWheel]; for (int i = 0; i < tisksPerWheel; i++) { tasks[i] = new NodeHeader(); } //定时任务 this.timer = new Timer(); } //开启时间轮旋转 public void start() { if (state.get()) { throw new IllegalArgumentException("Cannot be started once"); } TimerTask timerTask = new MoveCurrentTask(); timer.schedule(timerTask, 3, tickDuration); } //关闭时间轮 public boolean stop() { Timer timer = new Timer(); timer.cancel(); return true; } public static void main(String[] args) throws InterruptedException { SimpleTimeWheel simpleTimeWheel = new SimpleTimeWheel(5, 500); simpleTimeWheel.addTask(new MyTask()); simpleTimeWheel.start(); } //具体调度的执行 private void Execute() { List<Task> list = getAndClearTask(); if (list != null) { for (Task task : list) { if (task.isCanRun()) { executor.execute(task); } } } } //获取当前格中的所有任务 private List<Task> getAndClearTask() { int currentPlace = (int) current.get() % tisksPerWheel; synchronized (tasks[currentPlace]) { NodeHeader nodeHeader = tasks[currentPlace]; if (nodeHeader.isEmpty()) { return null; } else { List<Task> list = new ArrayList(); list.addAll(nodeHeader.map.keySet()); nodeHeader.clearTask(); return list; } } } //添加任务 public void addTask(Task task) { int place = getPlace(); synchronized (tasks[place]) { NodeHeader nodeHeader = tasks[place]; nodeHeader.addTask(task); } } //获取待添加任务所在槽位 private int getPlace() { int currentPlace = (int) current.get() % tisksPerWheel; if ((currentPlace - 1) < 0) { return tisksPerWheel - 1; } else { return currentPlace - 1; } } //操作该类时,请确保获取锁 final static class NodeHeader { //维持一个定时任务列表,在操作该变量之前请确保同步 private volatile Map<Task, Task> map = new HashMap<Task, Task>(); public NodeHeader() { map = new HashMap<Task, Task>(); } public boolean isEmpty() { return map.size() <= 0; } public void addTask(Task task) { map.put(task, task); } public void clearTask() { map.clear(); } } //核心任务,定时任务timer通过此timerTask,移动所指向格,并将所指向格的任务添加到线程池,共线程池执行 class MoveCurrentTask extends TimerTask { public void run() { SimpleTimeWheel.this.current.incrementAndGet(); SimpleTimeWheel.this.Execute(); } } }