• 教你实现多线程案例定时器


    目录

    什么是定时器???

    定时器的特点

    手动实现一个定时器

    定时器工作原理

    定时器实现解析


    什么是定时器???

    当我们在做计划的时候,有事就会定个闹钟或者利用待办事项来提醒你要做这件事了,并且哪件事安排的时间最早就先执行谁.而我们软件开发中的定时器也是一样的--------需要我们安排任务并且记录多长时间后执行此任务.

    在Java标准库中定时器是利用Timer类,通过调用timer类的schedule方法来表示多长时间后执行什么任务.

     

    •  schedule方法第一个参数是表示要执行的任务(TimerTask类这个类实现了Runnable接口),第二个参数表示多长时间后执行

    定时器的特点

    • 当我们使用定时器执行完任务时,程序不终止,因为定时器内部实现是利用多线程,内部还有线程在工作
    • 在使用定时器执行任务时,进行等待期间,不影响其他线程执行任务.
    • 定时器可以执行多个任务

    手动实现一个定时器

    定时器工作原理

    • 由于定时器可以执行多个任务,并且每个任务的执行时间可能不同,我们就需要为时间更早的优先执行,所以使用优先级阻塞队列(PriorityBlockingQueue)来保证线程安全,同时为任务执行顺序安排优先级.
    • 定时器类内部有核心方法schedule(),该方法表示要执行的任务以及多长时间后执行.
    • 由于有多个任务,我们要实现一个任务类来描述每个任务(任务里包括时间,以及要做什么任务)
    • 时间更早的任务先执行,时间晚的任务后执行,当插入的任务比队列中首任务时间短时就立即执行,当插入任务比队首元素时间长时,将其放回队列中进行等待.

    定时器实现解析

    • 准备任务类

    该任务类描述任务都要做什么,多长时间后执行此任务

    • 注意点: 初始化时间时,一定要使用绝对时间戳(也就是具体时间比如20220805XX时XX分我要做啥任务)
    • 使用优先级队列要重写comparable接口

    • Mytimer类内部构成

    •  使用线程来执行任务

    •  注意当队列为空时要使用wait等待,防止当插入任务时进行通知获取不到锁,就导致死锁问题
    • 使用synchronized保证线程安全,将整个操作打包成原子,防止在插入和等待时间又有任务插入,导致有时可能超时等待.
    • 当前任务时间早于或等于队首任务,立即执行,否则需要重新放回队列中,再次等待时间差的时间
    • 等使用wait等待时,同时在插入任务时,也要使用notify进行通知

    代码实现:

    1. //任务 : 任务是干啥的 需要多长时间
    2. class MyTask implements Comparable{
    3. private long time;//任务时长
    4. private Runnable command;//要做的任务
    5. public MyTask(Runnable command,long after){
    6. this.time= after+ System.currentTimeMillis();
    7. this.command = command;
    8. }
    9. public void run(){
    10. command.run();
    11. }
    12. public long getTime(){
    13. return this.time ;
    14. }
    15. @Override
    16. public int compareTo(MyTask o) {
    17. return (int) (this.time - o.time);
    18. }
    19. }
    20. public class MyTimer {
    21. //实现一个定时器
    22. //线程安全的优先级队列 --将存放的任务按照时间的优先级存放
    23. private PriorityBlockingQueue queue = new PriorityBlockingQueue<>();
    24. //设置锁对象
    25. public Object locker = new Object();
    26. private void schedule(Runnable command,long after){
    27. MyTask task = new MyTask(command,after);
    28. synchronized (locker){
    29. queue.put(task);
    30. locker.notify();
    31. }
    32. }
    33. //准备一个线程进行执行
    34. public MyTimer(){
    35. Thread t = new Thread(()->{
    36. while(true){
    37. try {
    38. //这里加锁是为了将其下面的操作打包为一个整体
    39. //防止容易出现在将任务放入队列中和等待之间又有任务加进来
    40. //导致出现等待时间过长
    41. synchronized (locker) {
    42. while (queue.isEmpty()) {
    43. //判断是否为空防止一开没有任务就弹出,就容易死锁
    44. //这里要wait释放锁,防止notify一直等不到锁
    45. locker.wait();
    46. }
    47. MyTask e = queue.take();
    48. long curTime = System.currentTimeMillis();//当前时间
    49. if (e.getTime() > curTime) {
    50. //如果弹出的任务时间还没有到当前时间,再次把它放入队列中
    51. //然后进行等待x.getTime - curTime
    52. queue.put(e);
    53. locker.wait(e.getTime()-curTime);
    54. }else {
    55. //时间到了立马执行
    56. e.run();
    57. }
    58. }
    59. } catch (InterruptedException e) {
    60. e.printStackTrace();
    61. }
    62. }
    63. });
    64. t.start();
    65. }
    66. //for test
    67. public static void main2(String[] args) {
    68. MyTimer timer = new MyTimer();
    69. timer.schedule(new Runnable() {
    70. @Override
    71. public void run() {
    72. System.out.println("我是");
    73. }
    74. },2000);
    75. timer.schedule(new Runnable() {
    76. @Override
    77. public void run() {
    78. System.out.println("小bit");
    79. }
    80. },3000);
    81. timer.schedule(new Runnable() {
    82. @Override
    83. public void run() {
    84. System.out.println("你好");
    85. }
    86. },1000);
    87. }
    88. //for test
    89. public static void main(String[] args) {
    90. MyTimer timer = new MyTimer();
    91. for(int i =0;i<10;++i){
    92. timer.schedule(new Runnable() {
    93. @Override
    94. public void run() {
    95. System.out.println("hello");
    96. }
    97. },1000);
    98. }
    99. System.out.println("其他任务");
    100. }
    101. }
  • 相关阅读:
    Linux :vim ,gcc ,makefile 三件套之vim的基本使用
    java毕业设计糖助手服务交流平台mybatis+源码+调试部署+系统+数据库+lw
    SPEC CPU2006 Benchmark Descriptions
    去除数组中的重复数据
    React基于monaco editor的在线代码编辑器开发
    使用单调栈来解决的一些问题
    使用jxls excel模板填充生成Excel,多sheet页处理
    2分钟搭建FastGPT训练企业知识库AI助理(Docker部署)
    JMeter —— 接口自动化测试(数据驱动)
    文件管理:文件存储空间管理
  • 原文地址:https://blog.csdn.net/m0_61210742/article/details/126180791