Java 定时器

目录

Java线程 主要看AQS、ReentrantLock、DelayQueue
DelayQueue
Java 线程池

了解该类的原理需要按照顺序学习前置知识:CAS->Unsafe->AQS->ReentrantLock->DelayQueue->ThreadPoolExecutor

一、ScheduledExecutorService

DelayQueue可以实现延时任务 ,但是需要手动创建线程,考虑到每次需要线程就创建一个线程,执行完run()中的方法后线程池就销毁,创建线程需要与操作系统交互,成本高 。ScheduledExecutorService就是将线程复用处理延时任务,提高效率。

ScheduledExecutorService用于多线程处理定时任务 ,是ThreadPoolExecutor的子类,但数据结构使用的是DelayQueue而不是BlockingQueue,各个类可以这么理解,ThreadPoolExecutor、ScheduledExecutorService是最顶层的组件:

AQS->ReentrantLock->BlockingQueue->ThreadPoolExecutor
AQS->ReentrantLock->DelayQueue->ScheduledExecutorService

如果要理解延迟的原理请查看:DelayQueue 笔记

1.延迟不循环任务schedule()

schedule(Runnable command, long delay, TimeUnit unit)

  • command:任务
  • delay:延迟时间
  • unit:延迟单位
java 复制代码
@Component
@Slf4j
public class MineExecutors {
    private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
    private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:sss");

    @PostConstruct
    public void init() {
        scheduler.schedule(() -> {
            try {
                log.info("开始执行...time {}", format.format(new Date()));
                Thread.sleep(1000);
                log.info("执行结束...time {}", format.format(new Date()));
            } catch (Exception e) {
                log.error("定时任务执行出错");
            }
        }, 5, TimeUnit.SECONDS);
		log.info("初始化成功 {}", format.format(new Date()));
    }

}

2.延迟循环任务scheduleWithFixedDelay()

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

  • command:任务
  • initialDelay:初始化完成后延迟多长时间执行第一次任务
  • delay:任务执行时间间隔
  • unit:单位
java 复制代码
@Component
@Slf4j
public class MineExecutors {

    private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);

    private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @PostConstruct
    public void init() {
        scheduler.scheduleWithFixedDelay(() -> {
            try {
                log.info("开始执行...time {}", format.format(new Date()));
                Thread.sleep(5000);
                log.info("执行结束...time {}", format.format(new Date()));
            } catch (Exception e) {
                log.error("定时任务执行出错");
            }
        }, 0, 3, TimeUnit.SECONDS);
        log.info("初始化成功 {}", format.format(new Date()));
    }

}

3.工作原理

  1. 实例化定时器对象,需要给定核心线程数。(定时器不存在非核心线程)。
  2. 外部线程(生产者) 调用schedule()方法向线程池的优先队列中提交任务。
  3. 每次提交一个任务,外部线程 调用addWorker(true)创建一个工作线程来执行这个任务。
  4. 核心线程创建后如果任务还没到期,核心线程会通过AQS等待队列 等待,直到任务到期或被唤醒。(注意优先队列和等待队列不是一个东西,优先队列是存放任务的共享资源,等待队列是AQS存放等待线程的)
  5. 当核心线程池中的线程已满时,外部线程调用workQueueOffer()把任务存储到优先队列 中,并唤醒等待队列 中的线程,等待队列中队首 的线程尝试从优先队列中拿到堆顶的过期任务,如果没过期那么继续等待。
  6. 存储任务基于堆的数组实现,可以存储任意多的任务,外部线程 存入任务时会判断数组是否溢出执行grow()扩容。
相关推荐
测试员周周6 小时前
【Appium 系列】第16节-WebView-H5上下文切换 — 混合应用的自动化难点
运维·开发语言·人工智能·功能测试·appium·自动化·测试用例
Mahir088 小时前
Spring 循环依赖深度解密:从问题本质到三级缓存源码级解析
java·后端·spring·缓存·面试·循环依赖·三级缓存
杜子不疼.8 小时前
【C++ AI 大模型接入 SDK】 - DeepSeek 模型接入(上)
开发语言·c++·chatgpt
加号38 小时前
【C#】 串口通信技术深度解析及实现
开发语言·c#
sycmancia9 小时前
Qt——编辑交互功能的实现
开发语言·qt
RyFit9 小时前
SpringAI 常见问题及解决方案大全
java·ai
石山代码9 小时前
C++ 内存分区 堆区
java·开发语言·c++
绝知此事10 小时前
【算法突围 01】线性结构与哈希表:后端开发的收纳术
java·数据结构·算法·面试·jdk·散列表
无风听海10 小时前
C# 隐式转换深度解析
java·开发语言·c#
一只大袋鼠10 小时前
Git 进阶(二):分支管理、暂存栈、远程仓库与多人协作
java·开发语言·git