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

【Java多线程】计时器Timer/ScheduledExecutorService的使用

在这里插入图片描述

🔍 开发者资源导航 🔍
🏷️ 博客主页: 个人主页
📚 专栏订阅: JavaEE全栈专栏

Timer

Timer 是 Java 提供的一个简单的任务调度工具(位于 java.util 包),用于在指定的时间执行任务(一次性或周期性执行)。

Timer 的主要作用

  • 定时任务:在指定的延迟后执行一次任务。

  • 周期性任务:按照固定的时间间隔重复执行任务

Timer 的核心方法

方法说明
schedule(TimerTask task, long delay)延迟 delay 毫秒后执行一次任务
schedule(TimerTask task, Date time)在指定的 Date 时间执行一次任务
schedule(TimerTask task, long delay, long period)延迟 delay 毫秒后开始,每隔 period 毫秒重复执行任务
scheduleAtFixedRate(TimerTask task, long delay, long period)延迟 delay 毫秒后开始,以固定速率(period 毫秒)重复执行任务
cancel()终止 Timer,取消所有已安排的任务

使用实例

import java.util.Timer;
import java.util.TimerTask;public class demo18 {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 1000");}}, 1000); // 1秒后执行timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 2000");}}, 2000); // 2秒后执行timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 3000");}}, 3000); // 3秒后执行}
}
 Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 1000");}}, 1000, 1000); // 每隔1s执行一次

缺点

  • 单线程执行:所有任务都在同一个线程中执行,如果一个任务执行时间过长,会影响其他任务的调度。

  • 异常影响全局:如果某个任务抛出未捕获的异常,整个 Timer 会终止,后续任务不会执行。

  • 时间精度依赖系统时钟:如果系统时间被调整(如手动修改时间),可能导致任务执行不准确。

ScheduledExecutorService

由于 Timer 的局限性,Java 5 引入了 ScheduledExecutorService(属于
java.util.concurrent 包),它使用线程池,更稳定、更灵活,推荐在新代码中使用。

创建方式

使用线程池的工厂类

创建单线程的ScheduledExecutorService,任务量少,需顺序执行
Executors.newSingleThreadScheduledExecutor()创建n个线程的ScheduledExecutorService,高并发任务,需并行执行
Executors.newScheduledThreadPool(n)创建n个线程的ScheduledExecutorService,并设置拒绝方法
ExecutorsScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)

直接创建

可以设置工厂方法,拒绝方法,以及核心数目
ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler)

推荐使用

  • 如果只是普通定时任务 → 推荐 Executors.newScheduledThreadPool()(更简洁)。

  • 如果需要定制线程池(如调整拒绝策略、线程工厂) → 使用 new ScheduledThreadPoolExecutor()。

使用方法

使用 ScheduledExecutorService 进行任务调度时,可以通过不同的方法设置任务的执行方式,主要包括
延迟执行、固定速率执行 和 固定延迟执行。

延迟执行(单次任务)

参数

schedule(Runnable command, long delay, TimeUnit unit)

特点

  • 任务 只会执行一次
  • 在指定的 delay 时间后执行。

使用场景:只需要在某个时间点执行一次的任务(如延迟初始化、超时任务)。

示例:

executor.schedule(() -> {System.out.println("Task runs after 3 seconds");
}, 3, TimeUnit.SECONDS);

固定速率执行(Fixed Rate)

参数:

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

特点:

  • 按照固定频率执行,不受任务执行时间影响。

  • 如果任务执行时间超过 period,下一次任务会 立即开始(可能并发执行)。

使用场景:适用于 严格周期性的任务(如定时数据同步)。

示例:

// 初始延迟 1 秒,之后每 2 秒执行一次(不管任务执行多久)
executor.scheduleAtFixedRate(() -> {System.out.println("Fixed Rate Task - " + System.currentTimeMillis());
}, 1, 2, TimeUnit.SECONDS);

固定延迟执行(Fixed Delay)

参数:

scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

特点:

  • 任务执行完成后,再等待 delay 时间后执行下一次。

使用场景:适用于 需要保证任务执行间隔 的场景(如心跳检测)

示例:

// 初始延迟 1 秒,每次任务结束后等 2 秒再执行下一次
executor.scheduleWithFixedDelay(() -> {System.out.println("Fixed Delay Task - " + System.currentTimeMillis());
}, 1, 2, TimeUnit.SECONDS);

手写一个Timer

参数

 Object locker = new Object();//锁private PriorityQueue<MytimerTask> queue = new PriorityQueue<>();

通过优先队列,来对时间进行排列。

schedule

 public void schedule(Runnable task, long delay) {synchronized (locker) {queue.offer(new MytimerTask(task, System.currentTimeMillis() + delay));locker.notify();}}

初始化方法

 public Mytimer() {Thread t1 = new Thread(()->{synchronized (locker){try {while (true) {while (queue.size() == 0) {//避免没有任务时的忙等locker.wait();}if (queue.peek().time <= System.currentTimeMillis()) {queue.peek().runnable.run();queue.poll();} else {//此处也是为了避免忙等//等待时间,虽然可能会错误唤醒,但是影响几乎可以忽略不计。locker.wait(queue.peek().time - System.currentTimeMillis());}}} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();}

此处的wait不能使用sleep来代替

  1. sleep的时候不会释放锁,到时候添加不了新的任务。
  2. sleep时长是固定的,如果等待时候添加了一个时间更早的任务,可能导致无法正确执行。而wait在添加新任务的时候会被唤醒一次。

感谢各位的观看Thanks♪(・ω・)ノ,如果觉得满意的话留个关注再走吧。

http://www.xdnf.cn/news/264799.html

相关文章:

  • mysql主从复制搭建,并基于‌Keepalived + VIP实现高可用
  • MARM:推荐系统中的记忆增强突破
  • C++ - 数据容器之 forward_list(创建与初始化、元素访问、容量判断、元素遍历、添加元素、删除元素)
  • Python爬虫实战:获取企信网指定公司基本工商数据并分析,为客户选择公司做参考
  • 封装pinia并引入pinia持久化工具(pinia-plugin-persistedstate)
  • HarmonyOS NEXT——DevEco Studio的使用(还没写完)
  • 如何基于HAL库进行STM32开发
  • 华为云Flexus+DeepSeek征文|DeepSeek-V3商用服务开通教程
  • Python 学习
  • 4.29-4.30 Maven+单元测试
  • 【LeetCode Hot100】二分查找篇
  • Swift:重构开发范式的现代编程语言
  • 《高性能MySQL》第1讲:MySQL架构
  • 音视频开发技术总结报告
  • 对比表格:数字签名方案、密钥交换协议、密码学协议、后量子密码学——密码学基础
  • 3.0/Q1,Charls最新文章解读
  • batch normalization和layer normalization区别
  • 循环缓冲区
  • QNAP Duplicati 备份 123云盘
  • Java接口全面教程:从入门到精通
  • ai之paddleOCR 识别PDF python312和paddle版本冲突 GLIBCXX_3.4.30
  • C与指针4——指针
  • 每天一道面试题@第五天
  • 第九课认识倍数
  • 【C++】模板进阶
  • C++/SDL 进阶游戏开发 —— 双人塔防(代号:村庄保卫战 20)
  • 多协议 Tracker 系统架构与传感融合实战 第四章 IMU 与 UWB 传感融合框架
  • 基于Springboot旅游网站系统【附源码】
  • 步进电机中断函数解释
  • rhce第二次作业