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

多线程篇七

多线程篇七

若笔者理解有误,欢迎交流指正⭐


定时器
什么是定时器

听到定时器,首先想到的是“闹钟”.到一个设置好的时间之后就执行某个指定好的代码.(在实际开发中非常常用,如网络通信【邮件发送】)
你在抢演唱会门票,已经到了支付页面,但是网突然崩了,页面显示让你等待,这下怎么办!!对于我们来说是不能无限的等待下去的,我们需要一个等待期限最好是尽快处理,此处的等待时间就通过定时器来实现了.

标准库中的定时器

标准库中提供了一个Timer类.其核心方法为schedule.(注意不要自命名Timer类)
schedule 包含两个参数. 第一个参数指定即将要执行的任务代码, 第二个参数指定多长时间之后 执行 (单位为毫秒).

上代码!

import java.util.Timer;
import java.util.TimerTask;public class TimeKeeper {public static void main(String[] args) {Timer timer = new Timer();       //匿名内部类 继承TimerTak并创建一个实例timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("Hello Keeper!");}},5000);System.out.println("Hello Main!");}
}

运行代码
请添加图片描述

发现先打印了"Hello Keeper!“等待五秒后打印’'Hellp Main”,Why?
可以通过代码观察到主线程执行schedule方法的时候讲Task放到timer对象中,timer中也包含一个线程("扫描线程”,等待的时间到了就会执行安排给扫描线程的任务)

那怎么线程没有结束呢?上源码!
请添加图片描述

Timer内部还有线程!
一个Timer中是可以安排多个任务的

定时器的实现
import java.util.PriorityQueue;//任务描述块
class MyTimerTask implements Comparable<MyTimerTask> {//需要一个执行的任务private Runnable runnable;//需要执行任务的时间private  long time;//传入“相对时间”public MyTimerTask(Runnable runnable,long delay) {this.runnable = runnable;this.time = System.currentTimeMillis() + delay;}@Overridepublic int compareTo(MyTimerTask o) {//这样写让队首元素是最小时间的值return (int)(this.time - o.time);//最大反过来 通过尝试来判断//return o.time - this.time;}public long getTime() {return time;}public Runnable getRunnable() {return runnable;}}class MyTimer {//存储任务的数据结构private PriorityQueue<MyTimerTask> queue = new PriorityQueue<MyTimerTask>();//使用这个对象作为锁对象private Object locker = new Object();public void schedule(Runnable runnable, long delay) {synchronized(locker) {queue.offer(new MyTimerTask(runnable, delay));locker.notify();}}//扫描线程
public MyTimer() {//创建线程Thread t = new Thread(() -> {//使用while 是为了在wait被唤醒时 再确认一下条件while(true) {try {synchronized(locker) {while(queue.isEmpty()) {locker.wait();}//比较当前队首元素是否可以执行了MyTimerTask task = queue.peek();long curTime = System.currentTimeMillis();if(curTime >= task.getTime()) {//达到时间可以执行task.getRunnable().run();//执行完就可以从队列中deletequeue.poll();}else {//没到执行任务的时间 等待下一次判定locker.wait(task.getTime() - curTime);}}}catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();
}
}
//定时器
public class TimeKeeper {public static void main(String[] args) {MyTimer timer = new MyTimer();timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("5000");}},5000);timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("4000");}},4000);timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("3000");}},3000);System.out.println("Game Start!");}
}

运行得到
image-20240921113003059

思路分析

1.Timer中需要有一个线程扫描任务是否到时间,是否执行.
2.需要一个数据结构,把所有的任务都保存起来
3.需要创建一个类通过类的对象描述一个任务(至少包含任务和时间)
相比ArrayList使用优先级队列更好【优先级队列时间复杂度可以达到O(1)】
咱都知道ArrayList(数组)遍历时会对每一个任务都进行遍历并且可能会有很多趟,这不是妥妥的资源浪费.而使用优先级队列可以给Timer中的任务“赋值”,最先执行时间最小的任务,其他任务就不能执行了.

Question

1."调试器"怎么使用?
靠谱一点的是打印日志【println】,避免打断点对线程正常工作的影响.

2.为什么使用wait不使用sleep?【避免忙等 消耗资源】
使用wait比sleep更好.主线程调用schedule添加新任务但还在等待过程,新的任务执行时间比最早的任务时间还早刚好可以使用schedule中的notify唤醒wait让循环再执行一遍

一点的是打印日志【println】,避免打断点对线程正常工作的影响.

2.为什么使用wait不使用sleep?【避免忙等 消耗资源】
使用wait比sleep更好.主线程调用schedule添加新任务但还在等待过程,新的任务执行时间比最早的任务时间还早刚好可以使用schedule中的notify唤醒wait让循环再执行一遍


未完待续🌟🌟🌟


http://www.mrgr.cn/news/31778.html

相关文章:

  • go反射深入学习
  • 数字IC后端低功耗设计实现案例分享(3个power domain,2个voltage domain)
  • 电商系统开发:Spring Boot框架实战
  • 机器学习day2-特征工程
  • C++清除所有输出【DEV-C++】所有编辑器通用 | 算法基础NO.1
  • 基本定时器---内/外部时钟中断
  • [已更新]2024华为杯数学建模研赛A题问题一二建模代码研究生数学建模
  • linux网络-----传输层
  • expressjs 的app.use,怎么使用?
  • 数据类型转换中存在的问题分析
  • armbian debian 系统安装overlayroot后无法启用
  • Java+Spring Cloud +UniApp 智慧工地源码,用户PC端、移动端数据同步,支持多端展示
  • Windows本地连接远程服务器并创建新用户详细记录
  • 【论文笔记】BEVNeXt: Reviving Dense BEV Frameworks for 3D Object Detection
  • TMS320F28335的定时器中断实验
  • 数据结构-顺序表
  • Linux常用命令(部分学习待继续补充)
  • (undone) 声音信号处理基础知识(2)
  • 【免杀】CS免杀——ps1免杀
  • 继承和多态
  • 聊聊通过阅读书籍类型来判断人
  • 【算法——二分查找】
  • 500元以内头戴式耳机哪款好?盘点500元以内百元宝藏品牌机型推荐
  • 系统架构设计师 - 案例特训专题 - 软件工程篇
  • Leetcode Hot 100刷题记录 -Day18(反转链表)
  • MongoDB在Linux系统中的安装与配置指南