【揭秘】ScheduledThreadPoolExecutor全面解析

发布时间:2024年01月23日

【揭秘】ScheduledThreadPoolExecutor全面解析 - 程序员古德

内容摘要

ScheduledThreadPoolExecutor能够高效地管理和复用线程资源,避免了大量线程的创建和销毁开销,从而提升了系统性能,同时,它提供了灵活的任务调度机制,支持延迟执行和固定频率执行,满足了各种复杂场景下的需求。

官方文档:https://docx.iamqiang.com/jdk11/api/java.base/java/util/concurrent/ScheduledThreadPoolExecutor.html

核心概念

ScheduledThreadPoolExecutor是一个非常实用的工具,它允许按照预定的计划执行命令或任务,假如,有一个电商平台,随着“双十一”购物狂欢节的临近,需要确保系统能够应对大量的定时任务,像发送促销提醒、检查订单状态、更新库存等。

比如(模拟业务场景),要在双十一当天的零点准时向所有注册用户发送一条促销短信,提醒他们来购物,不需要为每一个用户都单独设置一个定时器,只需要使用ScheduledThreadPoolExecutor,就可以轻松地安排这个任务,再比如,系统能够每隔一段时间自动检查未支付的订单,并在订单超时未支付时自动取消,同样可以使用ScheduledThreadPoolExecutor来实现,可以设定一个固定的间隔时间,比如每五分钟检查一次,然后让ScheduledThreadPoolExecutor按照这个计划周期性地执行任务。

使用ScheduledThreadPoolExecutor,可以轻松地管理和调度各种定时任务,确保它们在正确的时间点被执行,而不需要担心因为任务过多而导致的系统资源不足或任务冲突等问题。

使用案例

如下,是一个简单的示例,演示了如何使用 ScheduledThreadPoolExecutor 来使一个任务在固定的延迟之后执行,以及使一个任务以固定的频率重复执行,如下代码:

import java.util.concurrent.Executors;  
import java.util.concurrent.ScheduledExecutorService;  
import java.util.concurrent.TimeUnit;  
  
public class ScheduledThreadPoolExecutorExample {  
  
    public static void main(String[] args) {  
        // 创建一个ScheduledThreadPoolExecutor实例,指定线程池的大小  
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);  
  
        // 安排一个任务在固定的延迟之后执行  
        Runnable delayedTask = () -> System.out.println("Delayed task executed after 3 seconds");  
        executor.schedule(delayedTask, 3, TimeUnit.SECONDS);  
  
        // 安排一个任务以固定的频率重复执行  
        Runnable periodicTask = () -> System.out.println("Periodic task executed every 2 seconds");  
        executor.scheduleAtFixedRate(periodicTask, 0, 2, TimeUnit.SECONDS);  
  
        // 为了演示,让主线程睡眠一段时间,以便观察ScheduledThreadPoolExecutor的行为  
        try {  
            TimeUnit.SECONDS.sleep(10);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
  
        // 关闭executor  
        executor.shutdown();  
        try {  
            if (!executor.awaitTermination(800, TimeUnit.MILLISECONDS)) {  
                executor.shutdownNow();  
            }  
        } catch (InterruptedException e) {  
            executor.shutdownNow();  
        }  
    }  
}

在上面代码中,创建了一个 ScheduledExecutorService 实例,指定了线程池的大小为2,然后,安排了两个任务:一个是在3秒之后执行的延迟任务,另一个是每2秒执行一次的周期性任务。

如下输出结果:

Periodic task executed every 2 seconds  
Periodic task executed every 2 seconds  
Delayed task executed after 3 seconds  
Periodic task executed every 2 seconds  
Periodic task executed every 2 seconds

核心API

ScheduledThreadPoolExecutorThreadPoolExecutor 的一个子类,专门用于在给定的延迟后执行命令,或者定期执行命令,以下是 ScheduledThreadPoolExecutor 中一些重要方法的简要说明:

  1. schedule(Runnable command, long delay, TimeUnit unit):安排一个在给定的延迟后执行的单次命令,command 是要执行的任务,delay 是执行任务前的延迟时间,unit 是延迟时间的单位(如 TimeUnit.SECONDS 表示秒),返回一个 ScheduledFuture,该对象可以取消任务(如果尚未开始)。
  2. scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit),安排一个定期执行的任务,以固定的频率运行,command 是要执行的任务,initialDelay 是首次执行任务前的延迟时间,period 是连续任务执行之间的周期时间,unit 是时间单位,返回一个 ScheduledFuture,该对象可以取消任务,注意:如果任务的执行时间超过了指定的周期,那么下一次执行可能会延迟,但不会并发执行。
  3. scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit),安排一个定期执行的任务,但是在每次执行完毕后都有一个固定的延迟,command 是要执行的任务,initialDelay 是首次执行任务前的延迟时间,delay 是任务执行完毕和下一次任务开始之间的延迟时间,unit 是时间单位,返回一个 ScheduledFuture,该对象可以取消任务,注意:与 scheduleAtFixedRate 不同,scheduleWithFixedDelay 保证了任务之间的延迟,而不是任务开始的时间间隔。
  4. shutdown(),启动执行器的有序关闭,在该方法中,执行器将不再接受新任务,但会完成所有排队的任务。
  5. shutdownNow(),试图停止所有正在执行的任务,暂停处理那些尚未开始处理的任务,并返回等待执行的任务列表。
  6. isShutdown(),如果执行器已关闭,则返回 true
  7. isTerminated(),如果执行器关闭后所有任务都已完成,则返回 true
  8. awaitTermination(long timeout, TimeUnit unit),请求关闭的执行器终止,等待最多指定的时间让执行器完成所有任务,如果执行器在指定的时间内完全终止,则返回 true;否则返回 false
  9. getPoolSize(),返回线程池中的线程数量。
  10. getCorePoolSize(),返回线程池的核心大小,即即使在空闲时也保留在池中的线程数。
  11. setCorePoolSize(int corePoolSize),设置线程池的核心大小。

这些核心API提供了对任务调度的精细控制,包括任务的开始时间、执行频率以及线程池的大小和行为。

核心总结

【揭秘】ScheduledThreadPoolExecutor全面解析 - 程序员古德

ScheduledThreadPoolExecutor的优点在于能高效管理线程资源,支持灵活的任务调度,且内部实现了线程池,避免了大量线程创建和销毁的开销,它也有缺点,比如任务执行异常时默认会终止后续调度,需要额外处理,使用时建议明确任务性质,合理配置线程池大小,并处理好任务间的依赖和异常,

关注我,每天学习互联网编程技术 - 程序员古德

文章来源:https://blog.csdn.net/qusikao/article/details/135783401
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。