• 【javaEE】多线程初阶(Part7定时器)!!



    前言

    今天不学习,明天变垃圾

    本文内容主要是:多线程实例的【定时器】,定时器的实现其实是比较复杂的,建议一定要自己尝试写一遍并进行理解,多线程这块儿很重要。


    一、定时器简介

    1. 定时器就类似于闹钟。而代码中的定时器,通常是设定多长时间之后来执行某个动作(其实也就是具体的代码逻辑)
    2. 在具体的服务器开发中,客户端向服务器端发送请求之后就需要等待服务器端的响应,但是服务器端的响应时间是不确定的。
    3. 如果出现了客户端等待很久而服务器端依旧不响应的情况,客户端是不会死等下去的,如果一直死等下去,程序很可能就会卡死;因此客户端经常会设置一个“超过时间”,此时就使用定时器来实现。

    二、 标准库中的定时器Timer

    1. 标准库中的定时器 Timer类(使用的是java.util中的)。
    2. 而在Timer类中的一个重要的方法是schedule(TimerTask task, long delay)
      ① 参数1 TimerTask task是要安排的任务,其实就是一个Runnable接口,我们要做的就是继承这个TimerTask,然后重写run方法,从而指定要执行的任务。【注意!参数1是 new TimerTask() {…重写run方法},不是new Runnable() {…}】
      ② 参数2 long delay 就是指经过delay (ms)之后开始执行参数1任务task。
    3. 一个定时器可以同时安排多个任务!
    4. 执行代码会发现,在执行完task任务之后进程并没有退出,理由:Timer内部需要一组线程来执行注册的任务task,而这里的线程是前台线程,会影响进程退出。
    5. 【标准库实现】 参考代码:Demo3标准库实现定时器

    三、模拟实现定时器(难!)

    1. 自己实现【定时器Timer】
      1)创建一个类MyTimer,实现schedule方法,该方法中有两个参数,参考标准库中的schedule方法,一个参数是TimerTask task,一个参数是long delay
      2)写一个类MyTask来描述两个参数,该类要能够描述【任务信息以及什么时候执行该任务】。(尤其要注意执行时间time的赋值!!)
    2. 如何让MyTimer管理多个任务(标准类中的Timer类是可以管理多个任务的)?直接使用ArrayList来存储多个任务行不行?
      答:1)No。任务是有执行时间的,设置的时间越短的任务越要先执行。但是如果使用ArrayList的话元素的存储是无序的,找到时间最小的任务其实是不太方便的(遍历是需要花费时间的,时间复杂度O(N),在任务较多时就是不太方便的)
      2)所以:使用【优先队列:无论你按照什么顺序插入,出队列的顺序其实是固定的】。但是线程不安全,而schedule可能在多线程中调用。所以,为了保证线程安全,可以使用阻塞队列
      (因为BlockingQueue是一个接口,所以在实例化的时候就new 一个构造方法,该构造方法就用PriorityBlockingQueue()优先级阻塞队列 来实现)
    3. 【任务被安排到优先级阻塞队列中了,接下来就需要从队列中取元素了:创建一个单独的扫描线程,让这个线程不停的来检查队首元素时间是否到了,如果时间到了则执行该任务。】
    4. 由于阻塞队列无法阻塞式的取队首元素,所以:只能先取出任务再判定任务时间是否到了;如果时间没到就再把任务放回去
    5. 因为优先级队列进行存储元素的时候需要按照一定的比较规则,则此时应该在MyTask类中继承Comparable接口来重写compareTo方法规定比较方法,进而达到有序存储元素
      (还存在 【忙等】问题,使用wait和notify方法,注意要加锁以及wait的等待时间,以及同一对象!)
    6. 【多线程其实是比较复杂的,但是在cpp和java中多线程仍然是最基本的并发编程方式,一定要克服这个难关!!】
    7. 参考代码:Demo4
      Demo4真的重要!!!建议自己写一遍!
      面试题中多线程超级多!!重要!!
    8. 小结定时器实现:
      ① MyTimer 类提供的核心方法为 schedule, 用于注册一个任务, 并指定这个任务多长时间后执行。
      ② MyTask 类用于描述一个任务, 里面包含一个 Runnable 对象和一个 time(毫秒时间戳)
      这个对象需要放到 优先队列 中, 因此需要实现 Comparable 接口。
      ③ MyTimer 实例中, 通过 PriorityBlockingQueue 来组织若干个 MyTask 对象,
      通过 schedule 来往队列中插入一个个 MyTask 对象。
      ④ MyTimer 类中存在一个扫描线程, 一直不停的扫描队首元素, 看看是否能执行这个任务。(所谓 “能执行” 指的是该任务设定的时间已经到达了)
      ⑤ 引入一个对象, 借助该对象的 wait / notify 来解决 while (true) 的忙等问题(也就是不停扫描,浪费CPU)
      修改 扫描线程 的 run 方法, 引入 wait, 等待一定的时间;
      修改 MyTimer 的 schedule 方法, 每次有新任务到来的时候唤醒一下 扫描 线程. (因为新插入的任务可能是需要马上执行的)。

    THINK

    1. 多线程在面试中常考!!
    2. 定时器的模拟实现一定要自己能够写!!
    3. 注意定时器的实现逻辑。
    4. 定时器中重要的方法是schedule。
  • 相关阅读:
    新晋国产证书品牌——JoySSL
    如何更换war和jar包中的文件
    C语言 3 —— 输入输出
    新移科技发布基于联发科MT8390(Genio 700)平台的物联网 AI 核心板
    Java-API简析_java.util.PropertyPermission类(基于 Latest JDK)(浅析源码)
    Linux下进程间的通信--共享内存
    虚拟化与Docker基本概念与Docker的安装
    C/C++总结笔记——指针1:二级指针、空指针(NULL和nullptr)、野指针
    MySQL【聚合函数】
    Three.js中加载和渲染3D Tiles
  • 原文地址:https://blog.csdn.net/weixin_54150521/article/details/127690791