Java多线程之深入学习定时器(Timer)


提示:以下是本篇文章正文内容,Java系列学习将会持续更新

一、定时器

Timer类和TimerTask类

Timer定时器主要用于做定时任务或者按照一定的时间间隔做循环任务

java.util.Timer 作为定时器,用于启动定时任务。
java.util.TimerTask 实现了Runnable接口,需要重写**run()**方法,用于盛放我们要做的任务。

注意
①一个Timer定时器只会开启一个新线程。
②一个Timer定时器可以开启多个TimerTask定时任务,但这些任务只是在同一个线程下轮流执行的。

如何使用?

// 创建一个定时器
Timer timer = new Timer();

// 创建一个定时任务
TimerTask timerTask = new TimeTask() {
	@Override
	public void run() {
    	System.out.println("闹钟响了");
	}
};

// 延时1000ms后开始,每隔3000ms执行一次
timer.schedule(task, 1000, 3000);

// 启动定时任务的方法
timer.schedule(TimerTask task, long delay);
timer.schedule(TimerTask task, long delay, long period);

回到目录…

二、自己实现一个定时器

定时器原理

在这里插入图片描述
 ①其中 TaskQueue 是一个平衡二叉树堆实现的优先级队列,每个 Timer 对象内部有唯一一个 TaskQueue 队列。用户线程调用 timer 的 schedule 方法就是把 TimerTask 任务添加到 TaskQueue 队列,在调用 schedule 的方法时候 long delay 参数用来说明该任务延迟多少时间执行。
 ②TimerThread 是具体执行任务的线程,它从 TaskQueue 队列里面获取优先级最小的任务进行执行,需要注意的是只有执行完了当前的任务才会从队列里面获取下一个任务而不管队列里面是否有已经到了设置的 delay 时间,一个 Timer 只有一个 TimerThread 线程,所以可知 Timer 的内部实现是一个多生产者单消费者模型

代码实现

我的定时器

import java.util.concurrent.PriorityBlockingQueue;

public class MyTimer {
    // 存放延时任务的优先级队列
    private final PriorityBlockingQueue<MyTimerTask> queue = new PriorityBlockingQueue<>();
    // 定义一个锁
    private final Object newTaskComing = new Object();

    public MyTimer() {
        // 开始实施任务
        Worker worker = new Worker();
        worker.start();
    }
    // 定时器的启动方法
    public void schedule(MyTimerTask task, long delay) {
        // 该方法非工作线程调用
        task.runAt = System.currentTimeMillis() + delay;
        queue.put(task);
        synchronized (newTaskComing) {
            // 唤醒优先级最高的任务
            newTaskComing.notify();
        }
    }

    // 实际上实施任务的线程类
    class Worker extends Thread {

        @Override
        public void run() {
            while (true) {
                // 先从队列中获取任务
                MyTimerTask task = null;
                try {
                    task = queue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                // task 应该有个应该执行的时刻(不能记录 delay)
                long now = System.currentTimeMillis();
                long delay = task.runAt - now;
                if (delay <= 0) {
                    task.run();
                } else {
                    try {
                        // 应该在两种条件下醒来:
                        // 1. 有新的任务过来了(任务可能比当前最小的任务更靠前)
                        // 2. 没有新任务来,但到了该执行该任务的时候了
                        synchronized (newTaskComing) {
                            newTaskComing.wait(delay);
                        }

                        // 如果当前时间已经在要执行任务的时间之后了
                        // 说明任务的执行时间已过,所以应该去执行任务了
                        // 否则,先把这个任务放回去(因为时间还没到),再去取最小的任务
                        if (System.currentTimeMillis() >= task.runAt) {
                            task.run();
                        } else {
                            queue.put(task);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

任务类

public abstract class MyTimerTask implements Comparable<MyTimerTask> {

    long runAt;     // 这个任务应该在何时运行(记录为 ms 为单位的时间戳)

    abstract public void run();

    @Override
    public int compareTo(MyTimerTask o) {
        if (runAt < o.runAt) {
            return -1;
        } else if (runAt > o.runAt) {
            return 1;
        } else {
            return 0;
        }
    }
}

回到目录…


总结:
提示:这里对文章进行总结:
以上就是今天的学习内容,本文是Java多线程的学习,认识了定时器Timer,定时器的用法;以及深入了解了定时器的实现原理。之后的学习内容将持续更新!!!

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只咸鱼。。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值