【JUC】Executors 之 newSingleThreadScheduledExecutor 构建定时任务/延时任务

本文深入探讨了Java中使用Executors创建单线程定时任务的方法,包括延时任务、固定频率和固定延迟的循环任务,通过代码示例展示了schedule、scheduleAtFixedRate及scheduleWithFixedDelay的用法。
该文章已生成可运行项目,

Executors 之 newSingleThreadScheduledExecutor 构建定时任务/延时任务

schedule

延时任务,只执行一次
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);

  • Runnable command (the task to execute)
  • long delay 延迟执行时间(the time from now to delay execution)
  • TimeUnit unit delay参数的时间单位(the time unit of the delay parameter)

scheduleAtFixedRate

延时任务,并循环执行
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);

  • Runnable command(the task to execute)
  • long initialDelay 执行第一次的延迟时间(the time to delay first execution)
  • long period 连续执行的间隔时间(the period between successive executions)
  • TimeUnit unit 前两个参数的时间单位(the time unit of the initialDelay and period parameters)

scheduleWithFixedDelay

延时任务,并循环执行
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);

  • Runnable command(the task to execute)
  • long initialDelay 执行第一次的延迟时间(the time to delay first execution)
  • long delay 上一个执行器的终止与下一个执行器的开始之间的延迟(the delay between the termination of one execution and the commencement of the next)
  • TimeUnit unit delay参数的时间单位(the time unit of the delay parameter)

talk is cheap, show me the code.

System.out.format("[%s] - [%s] - main\n",
	DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now()),
	Thread.currentThread().getName());

// 创建一个单线程的任务调度池
ScheduledExecutorService singleThreadScheduledPool = Executors.newSingleThreadScheduledExecutor();

// 延时5秒后执行,只执行一次
singleThreadScheduledPool.schedule(() -> {
	System.out.format("[%s] - [%s] - schedule\n",
		DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now()),
		Thread.currentThread().getName());
}, 5, TimeUnit.SECONDS);

// 延时一秒后执行第一次,再循环执行(每隔5秒执行一次)
singleThreadScheduledPool.scheduleAtFixedRate(() -> {
	System.out.format("[%s] - [%s] - scheduleAtFixedRate\n",
		DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now()),
		Thread.currentThread().getName());
}, 1, 5, TimeUnit.SECONDS);

// 延时一秒后执行第一次,再循环执行(上一次执行结束延时5秒后再执行下次任务)
singleThreadScheduledPool.scheduleWithFixedDelay(() -> {
	System.out.format("[%s] - [%s] - scheduleWithFixedDelay\n",
		DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now()),
		Thread.currentThread().getName());
}, 1, 5, TimeUnit.SECONDS);

控制台输出

[2020/05/28 10:53:09] - [main] - main
[2020/05/28 10:53:10] - [pool-1-thread-1] - scheduleAtFixedRate
[2020/05/28 10:53:10] - [pool-1-thread-1] - scheduleWithFixedDelay
[2020/05/28 10:53:14] - [pool-1-thread-1] - schedule
[2020/05/28 10:53:15] - [pool-1-thread-1] - scheduleAtFixedRate
[2020/05/28 10:53:15] - [pool-1-thread-1] - scheduleWithFixedDelay
[2020/05/28 10:53:20] - [pool-1-thread-1] - scheduleAtFixedRate
[2020/05/28 10:53:20] - [pool-1-thread-1] - scheduleWithFixedDelay
[2020/05/28 10:53:25] - [pool-1-thread-1] - scheduleAtFixedRate
[2020/05/28 10:53:25] - [pool-1-thread-1] - scheduleWithFixedDelay
[2020/05/28 10:53:30] - [pool-1-thread-1] - scheduleAtFixedRate
[2020/05/28 10:53:30] - [pool-1-thread-1] - scheduleWithFixedDelay
[2020/05/28 10:53:35] - [pool-1-thread-1] - scheduleAtFixedRate
[2020/05/28 10:53:35] - [pool-1-thread-1] - scheduleWithFixedDelay
[2020/05/28 10:53:40] - [pool-1-thread-1] - scheduleAtFixedRate
[2020/05/28 10:53:40] - [pool-1-thread-1] - scheduleWithFixedDelay
[2020/05/28 10:53:45] - [pool-1-thread-1] - scheduleAtFixedRate
[2020/05/28 10:53:45] - [pool-1-thread-1] - scheduleWithFixedDelay
...
本文章已经生成可运行项目
在 `java.util.concurrent` 包中,`Phaser` 是一种灵活的同步屏障机制,允许线程在多个阶段(phase)之间进行协调。与 `CyclicBarrier` 和 `CountDownLatch` 相比,`Phaser` 支持动态注册和注销参与者,并且可以管理多个阶段的任务执行。 ### 实现阶段任务 为了实现多阶段任务,可以通过 `arriveAndAwaitAdvance()` 方法使每个线程到达当前阶段并等待其他参与者完成。当所有线程都到达后,`Phaser` 会自动进入下一阶段。以下是一个完整的示例: ```java import java.util.concurrent.Phaser; public class MultiPhaseTaskExample { public static void main(String[] args) { // 初始化 Phaser 并设置初始参与者的数量为3 Phaser phaser = new Phaser(3); // 定义一个包含多个阶段的任务 for (int i = 0; i < 3; i++) { final int threadId = i; new Thread(() -> { // 阶段 0 System.out.println(Thread.currentThread().getName() + " 正在执行阶段 0"); phaser.arriveAndAwaitAdvance(); // 等待所有线程完成阶段 0 // 阶段 1 System.out.println(Thread.currentThread().getName() + " 正在执行阶段 1"); phaser.arriveAndAwaitAdvance(); // 等待所有线程完成阶段 1 // 阶段 2 System.out.println(Thread.currentThread().getName() + " 正在执行阶段 2"); phaser.arriveAndAwaitAdvance(); // 等待所有线程完成阶段 2 }, "Thread-" + threadId).start(); } } } ``` 此代码定义了一个包含三个阶段的任务,每个线程都会依次执行这些阶段,并通过 `Phaser` 进行同步。 ### 动态调整参与者数量 如果需要动态地添加或移除参与者,可以使用 `register()` 和 `bulkRegister(int parties)` 来增加新的参与者,或者使用 `arriveAndDeregister()` 来减少参与者[^1]。例如: ```java // 动态注册一个新的参与者 phaser.register(); // 执行任务 new Thread(() -> { // 执行阶段逻辑 phaser.arriveAndAwaitAdvance(); }).start(); ``` ### 自定义阶段完成逻辑 `Phaser` 提供了 `onAdvance(int phase, int registeredParties)` 方法,可以在每次阶段完成时触发自定义逻辑。例如,可以在特定阶段结束时打印日志或执行清理操作: ```java Phaser phaser = new Phaser(3) { @Override protected boolean onAdvance(int phase, int registeredParties) { System.out.println("阶段 " + phase + " 已完成,当前注册参与者数量: " + registeredParties); return super.onAdvance(phase, registeredParties); } }; ``` 在这个例子中,每当一个阶段完成时,会输出当前阶段编号和注册的参与者数量[^2]。 ### 多线程场景下的灵活性 由于 `Phaser` 支持动态调整参与者数量,因此非常适合用于处理不确定线程数量的场景。例如,在某些情况下,某些线程可能提前退出任务,这时可以通过 `arriveAndDeregister()` 将其从同步屏障中移除: ```java if (someCondition) { phaser.arriveAndDeregister(); // 提前退出 } else { phaser.arriveAndAwaitAdvance(); // 继续等待 } ``` 这使得 `Phaser` 在复杂并发环境中具有更高的灵活性和适应性[^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值