栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

一、定时器

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 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 {
 

    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;
        }
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1028751.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号