ScheduledExecutorService创建newScheduledThreadPool线程池遇到的问题

本文探讨ScheduledExecutorService创建的newScheduledThreadPool线程池在处理任务时的特性:1) 如何使用scheduledFuture捕获并处理task异常;2) task运行超时与任务调度的关系;3) 当线程池大小小于任务数时,可能出现的任务执行异常情况。通过两个实例展示了线程池为1和2时的不同表现,并分享了相关的人工智能教程。
                最近线程池老是遇到执行两次的情况,故作了分析,情况如下
package test;import java.util.Date;import java.util.concurrent.ExecutionException;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ScheduledFuture;import java.util.concurrent.TimeUnit;public class Test static class EchoServer1 implements Runnable {  @Override  public void run() {   // TODO Auto-generated method stub   try {    Thread.sleep(10000);    i++;   } catch (InterruptedException e) {    // TODO Auto-generated catch block    e.printStackTrace();   }   if(i==3){    throw new java.lang.RuntimeException("Dasds");   }   System.out.println(i+"-"+10+"-"+Thread.currentThread().getName() +"-"+new Date());  }   } static int i =0static class EchoServer2 implements Runnable {  @Override  public void run() {   // TODO Auto-generated method stub      System.out.println(20+"-"+Thread.currentThread().getName() +"-"+new Date());  }   }  public static void main(String[] args){  ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);    executor.scheduleAtFixedRate(               new EchoServer2(),               0,               10,               TimeUnit.SECONDS);    ScheduledFuture<?> future = executor.scheduleAtFixedRate(                new EchoServer1(),                0,                5,                TimeUnit.SECONDS);    try {        try {     future.get();         } catch (InterruptedException e) {     // TODO Auto-generated catch block     e.printStackTrace();    }    } catch (ExecutionException e) {        Throwable cause = e.getCause();        cause.printStackTrace();        future.cancel(false);    } }}


1、可用scheduledFuture 捕获 task异常,并停止某个task,不影响其余task的运行。

2、若task运行时间大于间隔时间,则下一次task将在上一次task后马上运行,不会产生同时2个相同task的运行情况发生。

3、若线程池大小小于task大小,则若在情况2下,有另一条task占据了现有线程池(即阻塞了原task的一次运行),

则会造成 原task在另一条task结束后,执行两次。

线程池为1:

20-pool-1-thread-1-Mon Dec 29 21:34:08 CST 2014
1-10-pool-1-thread-1-Mon Dec 29 21:34:18 CST 2014
2-10-pool-1-thread-1-Mon Dec 29 21:34:28 CST 2014
20-pool-1-thread-1-Mon Dec 29 21:34:28 CST 2014
20-pool-1-thread-1-Mon Dec 29 21:34:38 CST 2014
20-pool-1-thread-1-Mon Dec 29 21:34:38 CST 2014
java.lang.RuntimeException: Dasds
at test.Test$EchoServer1.run(Test.java:23)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRunAndReset(Unknown Source)
at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
20-pool-1-thread-1-Mon Dec 29 21:34:48 CST 2014

线程池为2:

20-pool-1-thread-1-Mon Dec 29 21:33:13 CST 2014
20-pool-1-thread-1-Mon Dec 29 21:33:23 CST 2014
1-10-pool-1-thread-2-Mon Dec 29 21:33:23 CST 2014
20-pool-1-thread-1-Mon Dec 29 21:33:33 CST 2014
2-10-pool-1-thread-2-Mon Dec 29 21:33:33 CST 2014
20-pool-1-thread-1-Mon Dec 29 21:33:43 CST 2014
java.lang.RuntimeException: Dasds
at test.Test$EchoServer1.run(Test.java:23)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRunAndReset(Unknown Source)
at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
20-pool-1-thread-2-Mon Dec 29 21:33:53 CST 2014

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.youkuaiyun.com/jiangjunshow

<think>好的,我现在需要帮助用户解决Sonar扫描中关于ScheduledExecutorService的严重缺陷问题。首先,我需要理解用户的问题背景。用户在使用SonarQube进行代码扫描时,遇到了与ScheduledExecutorService相关的严重缺陷(可能是Critical或Blocker级别的)。常见的Sonar规则中,与线程池相关的问题可能包括资源未正确关闭、异常处理不当或线程泄漏等。 接下来,我应该回忆一下Java中ScheduledExecutorService的正确使用方法。记得在使用完线程池后必须调用shutdown()或shutdownNow()来释放资源,否则可能导致线程泄漏,进而引发内存泄漏或其他资源问题。Sonar的规则可能检测到未正确关闭的情况,从而报出严重缺陷。 然后,我需要参考用户提供的引用内容,看看是否有相关的信息。引用[1]提到《Java并发编程实战》这本书,可能涉及线程池的正确使用。引用[2]中提到了线程池和CompletableFuture,虽然主要讲异步任务,但线程池管理是相关的。引用[3]中的Mybatis缓存和Spring集成可能不直接相关,但分布式架构中的资源管理可能有间接联系。 现在,我需要思考常见的Sonar问题有哪些。比如,SchedulerExecutorService未关闭、未处理异常、使用不当的线程池参数(如核心线程数过多)等。用户的问题可能属于其中之一。例如,如果用户创建ScheduledExecutorService但没有在finally块中关闭,或者没有处理任务中的异常,导致Sonar报错。 接下来,我需要给出具体的解决方案。首先,确保在使用完线程池后正确关闭它。推荐在try-with-resources块中管理,但ScheduledExecutorService并不直接实现AutoCloseable,所以需要在finally中手动关闭。其次,处理任务中的未捕获异常,可以通过重写ThreadFactory,为线程设置UncaughtExceptionHandler。此外,合理配置线程池参数,避免使用无界队列或过多线程,防止资源耗尽。 然后,用户可能需要代码示例来具体实施这些解决方案。例如,展示如何正确关闭线程池,如何添加异常处理。同时,需要提醒用户注意其他可能的陷阱,比如任务执行时间过长影响调度,或者异常未被捕获导致任务静默失败。 最后,生成相关问题,帮助用户深入理解。比如线程池的最佳实践、Sonar其他并发问题的解决、如何调试线程泄漏等。</think>### 解决方案:Java ScheduledExecutorService Sonar 严重缺陷处理 SonarQube检测到`ScheduledExecutorService`相关严重缺陷的典型原因包括**线程池未关闭、异常未捕获、资源泄漏**。以下是分步解决策略: --- #### 1. **正确关闭线程池** **问题根源**: 未显式调用`shutdown()`或`shutdownNow()`会导致线程池资源无法释放,长期运行可能引发内存泄漏[^1]。 **修复方法**: 使用`try-finally`或`try-with-resources`(需包装实现`AutoCloseable`接口)确保关闭。 ```java ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); try { executor.schedule(() -> System.out.println("Task"), 5, TimeUnit.SECONDS); } finally { executor.shutdown(); // 温和关闭(等待任务完成) // 或 executor.shutdownNow(); // 立即终止 } ``` **注意**: - `shutdown()`:允许已提交任务完成,拒绝新任务 - `shutdownNow()`:尝试停止所有运行中的任务并返回未执行任务列表 --- #### 2. **处理任务中的未捕获异常** **问题根源**: 任务内未捕获的异常会导致线程终止且无日志,Sonar会视为潜在风险[^2]。 **修复方法**: 通过自定义`ThreadFactory`添加全局异常处理器。 ```java ThreadFactory factory = r -> { Thread t = new Thread(r); t.setUncaughtExceptionHandler((thread, ex) -> { System.err.println("Uncaught exception: " + ex.getMessage()); }); return t; }; ScheduledExecutorService executor = Executors.newScheduledThreadPool(2, factory); ``` --- #### 3. **避免不合理线程池配置** **Sonar规则触发场景**: - 使用`Executors.newSingleThreadScheduledExecutor()`可能导致任务堆积(无界队列) - 核心线程数过大(资源浪费) **优化建议**: 显式配置线程池参数,例如: ```java ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor( 2, // 核心线程数 new CustomThreadFactory(), new ThreadPoolExecutor.AbortPolicy() // 拒绝策略 ); executor.setRemoveOnCancelPolicy(true); // 取消任务后立即移除 ``` --- #### 4. **补充代码示例(完整生命周期管理)** ```java public class ScheduledTaskManager { private ScheduledExecutorService executor; public void init() { executor = new ScheduledThreadPoolExecutor(2, new CustomThreadFactory()); } public void scheduleTask(Runnable task, long delay) { executor.schedule(task, delay, TimeUnit.SECONDS); } public void shutdown() { if (executor != null) { executor.shutdown(); try { if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { executor.shutdownNow(); } } catch (InterruptedException e) { executor.shutdownNow(); Thread.currentThread().interrupt(); } } } } ``` --- ### 常见Sonar规则及对应措施 | Sonar规则ID | 问题描述 | 解决方案 | |-------------|----------|----------| | S2095 | 资源未关闭 | 添加`shutdown()`逻辑 | | S2142 | 未捕获异常 | 设置`UncaughtExceptionHandler` | | S2127 | 线程池参数不合理 | 使用`ThreadPoolExecutor`自定义配置 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值