简易时间轮的实现

在处理大量的延迟任务的时候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();

        }
    }


}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值