银川网站建站百度竞价推广怎么做效果好
文章目录
- 什么是定时器
- 标准库中的定时器
- 实现定时器
什么是定时器
定时器是一种编程工具,用于特定时间或固定时间间隔执行任务(代码逻辑),其核心功能是管理任务的调度和执行
标准库中的定时器
- Timer 和 TimerTask 类
定位:早期的单线程定时器实现,适用于简单场景。
核心类:
Timer:用于调度任务。
TimerTask:抽象类,需继承并实现 run() 定义任务逻辑。
实现定时器
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;class Mytask implements Comparable<Mytask>{private Runnable runnable;// 定义任务执行时间private long time;public Mytask(Runnable runnable,long delay){if(runnable==null){try{throw new IllegalAccessException("任务不能为空");} catch (IllegalAccessException e) {throw new RuntimeException(e);}}if(delay<0){try {throw new IllegalAccessException("时间不能小于0");} catch (IllegalAccessException e) {throw new RuntimeException(e);}}this.runnable=runnable;//计算出任务的具体时间this.time=delay+System.currentTimeMillis();}public Runnable getRunnable() {return runnable;}public long getTime() {return time;}@Overridepublic int compareTo(Mytask o) {if(this.getTime()-o.getTime()>0)return 1;else if(this.getTime()-o.getTime()==0)return 0;else return -1;}
}public class MyTimer {//定义线程内容private PriorityBlockingQueue<Mytask> priorityBlockingQueue=new PriorityBlockingQueue<>();public MyTimer() {//扫描线程Thread th1 = new Thread (()-> {while (true) {try {Mytask take = priorityBlockingQueue.take();//判断有没有到时间long times = System.currentTimeMillis();if (times >= take.getTime()) {//时间到了执行任务take.getRunnable().run();} else {long waittime = take.getTime() - times;//没有到时间放回阻塞队列priorityBlockingQueue.put(take);synchronized (this) {//进行休眠this.wait(waittime);}}} catch (InterruptedException e) {throw new RuntimeException(e);}}});th1.start();//创建一个后台线程Thread thread = new Thread (()->{while (true) {synchronized (this) {notifyAll();}//休眠一会try {TimeUnit.MICROSECONDS.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//设置为后台线程thread.setDaemon(true);thread.start();}public void schedule(Runnable runnable,long time) {//构建一个Mytask对象Mytask mytask=new Mytask(runnable,time);//放入阻塞数组priorityBlockingQueue.put(mytask);//唤醒等待线程synchronized (this){this.notifyAll();}}
}
这里要注意当将锁在加在整个while(扫描线程)时会产生死锁
/扫描线程Thread th1 = new Thread (()-> {synchronized (this) {while (true) {try {Mytask take = priorityBlockingQueue.take();//判断有没有到时间long times = System.currentTimeMillis();if (times >= take.getTime()) {//时间到了执行任务take.getRunnable().run();} else {long waittime = take.getTime() - times;//没有到时间放回阻塞队列priorityBlockingQueue.put(take);//进行休眠this.wait(waittime);}} catch (InterruptedException e) {throw new RuntimeException(e);}}}});
引起死锁的原因
锁的持有与阻塞调用:
扫描线程 th1 的整个循环被包裹在 synchronized(this) 块中。
当队列为空时,priorityBlockingQueue.take() 会阻塞,但此时 th1 仍持有 this 锁。
其他线程(如主线程调用 schedule)需要获取 this 锁才能添加任务,但无法获得锁,导致它们被阻塞。
互相等待的僵局:
th1 在等待队列中有任务(被 take() 阻塞),但其他线程无法添加任务(因为它们需要 this 锁)。
其他线程在等待 th1 释放锁,而 th1 在等待其他线程添加任务,形成死锁。
1.synchronized和wait的使用:
在MyTimer类的构造方法中,扫描线程t1并使synchronized(this)进行同步,台线程 (thread) 也使用 synchronized (this) 来调用 notifyAll()。
2.wait 和 notifyAll 的逻辑
在从队列中拿到线程任务时如果线程任务还没有到会调用wait()进行等待,
在主线程
后台线程 (thread) 也在尝试调用 notifyAll(),但它是在 synchronized (this) 块中执行的。如果此时没有其他线程持有 MyTimer 对象的锁,后台线程将无法执行 notifyAll()。所以锁得不到释放
任务的执行时间:
3.如果 Mytask 的执行时间设置得非常短(例如 0 毫秒),可能会导致 th1 线程不断地将任务放回队列并调用 wait(),而后台线程可能无法及时调用 notifyAll(),从而导致 th1 永远处于等待状态。