JavaEE线程安全定时器模式任务

网友投稿 291 2022-07-22


目录前言1.描述任务2.组织任务3.执行时间到了的任务

前言

像是一个闹钟定时,在一定时间之后被唤醒并执行某个之前设定好的任务,join(指定超时时间),sleep(指定休眠时间)都是基于系统内部的定时器来实现的。java.util.Timer核心方法就一个,schedule参数有两个:任务是啥(一段代码),多长时间之后执行

public class 定时器 {

public static void main(String[] args) {

Timer timer = new Timer();

timer.schedule(new TimerTask() {

@Override

public void run() {

System.out.println("hello timer");

}

}, 3000);

}

}

Timer内部组成

1.描述任务

创建一个专门的类来表示一个定时器的任务TimerTask,这个MyTask类的比较规则不是默认存在的,需要我们手动指定按照时间大小来比较的。

//创建一个类表示一个任务

class MyTask{

//任务描述

private Runnable runnable;

//任务具体啥时候干

private long time;

//after是一个时间间隔,不是觉得时间戳的值

public MyTask(Runnable runnable, long after){

this.runnable = runnable;

this.time = System.currentTimeMillis() + after;

}

public void run(){

runnable.run();

}

}

2.组织任务

通过一定的数据结构把一些任务给放到一起,标准库有一个专门的数据结构PriorityQueue,这里用到的数据结构是PriorityBlockingQueue,及带有优先级又带有阻塞队列。此处的队列要考虑到线程安全问题,可能在多个线程里进行注册任务,同时还有一个专门的线程来取任务执行,此时的队列就需要注意线程安全问题。其次为了避免盲等的现象,可以使用wait这样的机制指定等待时间时间到了自然唤醒,计算出当前时间和任务目标的时间差即可。既然是指定一个等待时间为啥不用sleep而是用wait,sleep不能被中途唤醒,wait能够被中途唤醒。在等待过程中可能有新的任务插入,新的任务是可能出现在之前所有任务的最前面,在schedule操作中就需要加上一个notify操作。

3.执行时间到了的任务

需要执行时间最靠前的任务,就需要一个线程不停地去检查当前优先队列的对手元素,看看当前最靠前的任务是不是时间到了

class MyTask implements Comparable{

//任务描述

private Runnable runnable;

//任务具体啥时候干

private long time;

//delay是一个时间间隔,不是绝对时间戳的值

public MyTask(Runnable runnable, long delay){

this.runnable = runnable;

this.time = System.currentTimeMillis() + delay;

}

public void run(){

runnable.run();

}

public long getTime(){

return time;

}

@Override

public int compareTo(MyTask o) {

//小的在前

return (int)(this.time - o.time);

}

}

class MyTimer{

private Object locker = new Object();

//定时器内不要能够存放多个任务

private PriorityBlockingQueue queue = new PriorityBlockingQueue<>();

public void schedule(Runnable runnable, long delay){

MyTask task = new MyTask(runnable, delay);

queue.put(task);

//每次任务插入成功之后都唤醒一下扫描线程,让线程重新检查队首的任务是否时间到要执行

synchronized (locker){

locker.notifygHDZFQc();

}

}

public MyTimer(){

Thread t = new Thread(() ->{

while(true){

try{

//先取出队首元素

MyTask task = queue.take();

//在比较一下看看当前这个任务时间到了没

long curTime = System.currentTimeMillis();

if(curTime < task.getTime()){

//时间没到把任务赛回到队列中

queue.put(task);

//制定一个等待时间

synchronized (locker){

locker.wait(task.getTime() - curTime);

}

}else{

//时间到了执行任务

task.run();

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

tgHDZFQc.start();

}

}

public class 定时器 {

public static void main(String[] args) {

MyTimer myTimer = new MyTimer();

myTimer.schedule(new Runnable() {

@Override

public void run() {

System.out.println("hello timer");

}

}, 3000);

myTimer.schedule(new Runnable() {

@Override

public void run() {

System.out.println("hello ");

}

}, 2000);

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java超详细讲解ArrayList与顺序表的用法
下一篇:Java连接Redis全过程讲解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~