当前位置: 首页 > article >正文

定时器(java)

文章目录

    • 什么是定时器
    • 标准库中的定时器
    • 实现定时器

什么是定时器

定时器是一种编程工具,用于特定时间或固定时间间隔执行任务(代码逻辑),其核心功能是管理任务的调度和执行

标准库中的定时器

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

    @Override
    public 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 永远处于等待状态。


http://www.kler.cn/a/600754.html

相关文章:

  • python每日十题(10)
  • JS—script标签加载:1分钟掌握async与defer
  • TensorDataser和DataLoader的解释与使用
  • 最长公共子序列LCS -- 全面分析版
  • 爱普生SG-3031CMA有源晶振在汽车雷达中的应用
  • vue2相关 基础命令
  • [NO-WX179]基于springboot+微信小程序的在线选课系统
  • W、M、C练题笔记(持续更新中)
  • 适合各个层次的 7 个计算机视觉项目【1】:植物病害检测
  • 内核编程十二:打印内核态进程的属性
  • 传统 embedding vs. P-Tuning 里的 embedding
  • (二)手眼标定——概述+原理+常用方法汇总+代码实战(C++)
  • 稳定运行的以Microsoft Azure Cosmos DB数据库为数据源和目标的ETL性能变差时提高性能方法和步骤
  • 深入解析 C++20 中的 std::bind_front:高效函数绑定与参数前置
  • 【蓝桥杯每日一题】3.25
  • MySQL数据库中常用的命令
  • 竞品已占据市场先机,如何找到差异化突破口
  • Next.js 中间件鉴权绕过漏洞 (CVE-2025-29927)
  • showdoc在服务器docker部署后如何关闭注册功能
  • XSS复现漏洞简单前八关靶场