自己实现定时器

思路:

1.由于定时器涉及到时间问题。所以在线程执行时需要判断时间是否允许,而且又是在多线程环境下,所以我们采用优先级阻塞队列来存取任务。
2.存放的任务我们定义为 MyTimerTask 类,而且要重写 Comparable 接口来确定优先级。
3.和实现前面的线程池方法类似,我们在创建定时器对象是直接确定线程池的大小和优先级阻塞队列的大小,并且直接启动线程。线程的 run 方法也是从优先级阻塞队列中取任务并运行。
4.创建 schedule 方法,向优先级阻塞队列中存入任务类。

参考代码:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.PriorityBlockingQueue;

public class MyTimerPool {

    // 优先级阻塞式队列,存放的元素需要实现Comparable接口
    // MyTimerTask是根据next下次执行时间比较的,优先获取next最小的
    private PriorityBlockingQueue<MyTimerTask> workQueue;
    // 执行的线程(类似固定线程池)
    private MyTimerThread[] threads;

    // 和线程池实现逻辑类似
    public MyTimerPool(int capacity, int size){
        this.threads = new MyTimerThread[capacity];
        workQueue = new PriorityBlockingQueue<>(size);
        for(int i=0; i<capacity; i++){
            threads[i] = new MyTimerThread(workQueue);
            threads[i].start();
        }
    }
    // 执行定时任务
    public void schedule(Runnable task, long delay, long period){
        workQueue.put(new MyTimerTask(task, delay, period));
        // 当前传入的任务,下次执行时间可能是最小的,所以
        // 需要通知线程,重新从阻塞队列中获取元素
        synchronized (workQueue){
            workQueue.notifyAll();
        }
    }

    public static class MyTimerThread extends Thread{

        private PriorityBlockingQueue<MyTimerTask> workQueue;
        public MyTimerThread(PriorityBlockingQueue<MyTimerTask> workQueue) {
            this.workQueue = workQueue;
        }

        @Override
        public void run() {
            try {
                while(true){
                    // 阻塞式队列take()方法是阻塞式的,poll()是非阻塞式
                    MyTimerTask myTimerTask = workQueue.take();
                    long current = System.currentTimeMillis();
                    long next = myTimerTask.next;
                    if(current < next){
                        // 等待下次执行时间到了,或者被通知到
                        synchronized (workQueue){
                            workQueue.wait(next - current);
                            // put()方法是阻塞式的,offer()是非阻塞的
                            workQueue.put(myTimerTask);
                        }
                    } else {
                        Date date = new Date(next);// 打印下次执行时间
                        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        System.out.println("date="+df.format(date));

                        myTimerTask.task.run();
                        if(myTimerTask.period > 0){
                            myTimerTask.next += myTimerTask.period;
                            workQueue.put(myTimerTask);
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static class MyTimerTask implements Comparable<MyTimerTask>{

        private long next;// 下次执行时间
        private Runnable task;
        private long period;

        public MyTimerTask(Runnable task, long delay, long period) {
            this.next = System.currentTimeMillis() + delay;
            this.task = task;
            this.period = period;
        }

        @Override
        public int compareTo(MyTimerTask o) {
            return Long.compare(next, o.next);
        }
    }

    public static void main(String[] args) {
        MyTimerPool pool = new MyTimerPool(3, 1000);
        pool.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("明天要答辩");
            }
        }, 0, 1000);
        pool.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("后天要放假");
            }
        }, 1500, 3000);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值