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

定时器(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.dtcms.com/a/90667.html

相关文章:

  • Linux安装MySQL数据库并使用C语言进行数据库开发
  • 【从零实现Json-Rpc框架】- 项目设计篇
  • C语言指针(二)
  • 有哪一些解放生产力的AI工具【前端】
  • GAMES101-现代计算机图形学入门(Assignment5)
  • 练习:自动驾驶
  • Linux中的基本开发工具(上)
  • 系统与网络安全------网络应用基础(3)
  • 图解CNN、RNN、LSTM
  • 【杂谈】-人工智能驱动的编码:提升效率还是增加网络安全隐患?
  • c++ primer 阅读手记 第三章
  • js中async+await+promise的用法及常见问题总结
  • Linux多线程详解
  • Docker镜像相关命令(Day2)
  • 【大模型】数字人 EchoMimicV2 的环境配置和使用
  • 基于Logisim的汉字显示模拟实验
  • 详细比较StringRedisTemplate和RedisTemplate的区别及使用方法,及解决融合使用方法
  • OLLVM 增加 CC++ 字符串加密功能
  • std::unordered_map和 std::map的区别
  • 代码随想录算法训练营第十一天| 150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素
  • leetcode 20.有效括号
  • 网络运维学习笔记(DeepSeek优化版) 023 HCIP-Datacom OSPF邻居建立过程、四种网络类型、OSPF高级配置、LSA类型与管理
  • 企业级部署zabbix分布式监控系统
  • C++数据结构(搜索二叉树)
  • 【SOC 芯片设计 DFT 学习专栏 -- IDDQ 测试 与 Burn-In 测试】
  • 使用CSS3实现炫酷的3D视差滚动效果
  • 综合小实验之电视机
  • <数据集>手势识别数据集<目标检测>
  • fpga pcie
  • javaSE.多维数组