Java并发编程——线程池的使用(五)延时执行的线程池ScheduledExecutorService

本文介绍了ScheduledExecutorService的延时执行及循环执行功能,并探讨了ScheduledThreadPoolExecutor的使用方法及其提供的高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、ScheduledExecutorService的延时执行功能

ScheduledExecutorService是延时执行的线程池,推荐用ScheduledExecutorService代替timer定时器。
创建一个ScheduledExecutorService很简单


ScheduledExecutorService service = Executors.newScheduledThreadPool(num);

延时n秒执行:

//延时n秒执行
service.schedule(Runnable, n, TimeUnit.SECONDS);
service.schedule(Callable, n, TimeUnit.SECONDS);

栗子:

 public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
        System.out.println("开始任务");
        //延时3秒执行
        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务");
            }
        }, 3, TimeUnit.SECONDS);
    }

log:

12-25 16:46:12.700 30954-30954/lbx.myapplication I/System.out: 开始任务
12-25 16:46:15.710 30954-31120/lbx.myapplication I/System.out: 执行任务

看下log的时间,可以发现,Runnable里的代码是在3秒后执行的。

二、ScheduledExecutorService的循环执行功能

//循环执行任务,首先延时m秒执行,n秒循环一次
service.scheduleAtFixedRate(Runnable, m, n, TimeUnit.SECONDS);

栗子:

    public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
        System.out.println("开始任务");
        //延时3秒执行,每1秒执行一次
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("执行任务");
            }
        }, 3, 1, TimeUnit.SECONDS);
    }

log:

12-25 16:49:56.000 7698-7698/lbx.myapplication I/System.out: 开始任务
12-25 16:49:59.000 7698-7847/lbx.myapplication I/System.out: 执行任务
12-25 16:50:00.000 7698-7847/lbx.myapplication I/System.out: 执行任务
12-25 16:50:01.000 7698-8406/lbx.myapplication I/System.out: 执行任务
12-25 16:50:02.000 7698-8406/lbx.myapplication I/System.out: 执行任务
12-25 16:50:03.000 7698-8406/lbx.myapplication I/System.out: 执行任务
12-25 16:50:04.000 7698-8406/lbx.myapplication I/System.out: 执行任务

可以发现,刚开始演示了三秒,后续每1秒执行了一次Runnable里的代码逻辑。

三、ScheduledThreadPoolExecutor的使用

ScheduledThreadPoolExecutor是ScheduledExecutorService的子类,

ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(num);

它有以下常用的方法:

//获取未完成的任务队列
executor.getQueue();
//移除任务队列中的任务  future = executor.scheduleAtFixedRate/scheduleWithFixedDelay
executor.remove((Runnable) future);
//取消任务队列中的schedule任务,但不会在队列中删除,即getQueue的数量不会减1,executor.setRemoveOnCancelPolicy(true)的时候减1
boolean cancel = future.cancel(true);
//schedule任务是否取消
future.isCancelled()
//延时的schedule在shutdown后,不会继续执行没到时间的任务,默认是true,会执行一次正在倒计时的任务再结束
executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
//延时的scheduleAtFixedRate/scheduleWithFixedDelay在shutdown后,不会继续执行没到时间的任务,默认是true,会执行一次正在倒计时的任务再结束
executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
### Java 中异步线程的实现方式与使用指南 在 Java 编程中,异步操作是一种常见的需求,尤其是在处理耗时任务或需要提高程序性能的情况下。下面详细介绍几种常用的 Java 异步线程实现方式及其具体使用方法。 #### 1. 使用 `ScheduledExecutorService` 实现异步延时 Java 提供了强大的并发工具包 `java.util.concurrent`,其中的 `ScheduledExecutorService` 是一种非常方便的方式用于执行定时或周期性的任务。它可以通过调度线程池来管理多个异步任务[^1]。 下面是基于 `ScheduledExecutorService` 的简单代码示例: ```java import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ScheduledTaskExample { public static void main(String[] args) { ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); Runnable task = () -> System.out.println("异步任务被执行"); // 延迟2秒后执行任务 scheduler.schedule(task, 2, TimeUnit.SECONDS); // 关闭调度器 scheduler.shutdown(); } } ``` 此代码片段展示了一个简单的延迟任务,在主线程启动后的两秒钟内不会打印任何内容,之后会输出指定的消息。 --- #### 2. 利用 Spring Framework 的异步支持 Spring 框架提供了内置的支持机制来简化异步编程模型。通过标注 `@Async` 注解的方法,默认会在独立的线程中运行[^4]。 要启用该特性,需配置如下内容: - 添加 `@EnableAsync` 注解到任意一个配置类上; - 方法签名前加上 `@Async` 注解即可让其变为异步调用。 以下是一个典型的例子: ```java import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class AsyncService { @Async public void performAsyncOperation() throws InterruptedException { Thread.sleep(2000); // Simulate a long-running operation. System.out.println(Thread.currentThread().getName() + ": 完成了异步操作"); } } ``` 注意:如果希望捕获异常或者返回结果,则可以考虑结合 `CompletableFuture<T>` 或者其他回调模式一起工作。 --- #### 3. 防止上下文丢失——Nepxion Discovery Agent 工具的应用 当涉及到复杂的业务逻辑时,尤其是跨线程传递共享状态(比如用户身份认证信息),单纯依靠传统的多线程技术容易引发数据丢失问题。此时可引入第三方库 Nepxion Discovery Agent 来解决此类难题[^3]。 例如,借助它的自动传播能力,即使是在不同的线程之间切换也能保持一致的行为表现而无需额外编码维护这些细节部分。 --- #### 4. 流式推送场景下的解决方案 —— ResponseBodyEmitter 对于某些特定应用场景下(如 WebSocket 替代方案之一),可能还需要考虑到长时间连接以及分批次传输大数据量等情况。这时就可以采用 Spring MVC 提供的一种特殊响应类型叫做 `ResponseBodyEmitter`[^4]。 实例演示如何利用这种技术完成文件下载过程中的进度更新报告功能: ```java @RestController @RequestMapping("/stream") public class StreamController { @GetMapping(value = "/download", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public ResponseEntity<ResponseBodyEmitter> downloadFile() { final ResponseBodyEmitter emitter = new ResponseBodyEmitter(); CompletableFuture.runAsync(() -> { try { for (int i = 0; i < 5; ++i) { Thread.sleep(1000L); emitter.send(("Progress: " + ((i + 1)*20)).getBytes()); } emitter.complete(); } catch(Exception e){ emitter.completeWithError(e); } }); return ResponseEntity.ok(emitter); } } ``` 以上代码实现了每秒发送一次当前百分比直到达到百分之百为止的效果。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值