Java使用ExecutorService来停止线程服务

作者:flydean 时间:2023-01-25 12:10:56 

使用ExecutorService来停止线程服务

之前的文章中我们提到了ExecutorService可以使用shutdown和shutdownNow来关闭。

这两种关闭的区别在于各自的安全性和响应性。shutdownNow强行关闭速度更快,但是风险也更大,因为任务可能正在执行的过程中被结束了。而shutdown正常关闭虽然速度比较慢,但是却更安全,因为它一直等到队列中的所有任务都执行完毕之后才关闭。

使用shutdown

我们先看一个使用shutdown的例子:


 public void useShutdown() throws InterruptedException {
   ExecutorService executor = Executors.newFixedThreadPool(10);

Runnable runnableTask = () -> {
     try {
       TimeUnit.MILLISECONDS.sleep(300);
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
   };

executor.submit(runnableTask);
   executor.shutdown();
   executor.awaitTermination(800, TimeUnit.MILLISECONDS);
 }

awaitTermination将会阻塞直到所有正在执行的任务完成,或者达到指定的timeout时间。

使用shutdownNow

当通过shutdownNow来强行关闭ExecutorService是, 它会尝试取消正在执行的任务,并返回所有已经提交但是还没有开始的任务。从而可以将这些任务保存起来,以便以后进行处理。

但是这样我们只知道了还没有开始执行的任务,对于那些已经开始执行但是没有执行完毕却被取消的任务我们无法获取。

我们看下如何获得开始执行但是还没有执行完毕的任务:


public class TrackingExecutor extends AbstractExecutorService {
 private final ExecutorService executorService;
 private final Set<Runnable> taskCancelledAtShutdown= Collections.synchronizedSet(new HashSet<Runnable>());

public TrackingExecutor(ExecutorService executorService){
    this.executorService=executorService;
 }
 @Override
 public void shutdown() {
   executorService.shutdown();
 }

@Override
 public List<Runnable> shutdownNow() {
   return executorService.shutdownNow();
 }

@Override
 public boolean isShutdown() {
   return executorService.isShutdown();
 }

@Override
 public boolean isTerminated() {
   return executorService.isTerminated();
 }

@Override
 public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
   return executorService.awaitTermination(timeout,unit);
 }

@Override
 public void execute(Runnable command) {
   executorService.execute(() -> {
     try {
       command.run();
     }finally {
       if(isShutdown() && Thread.currentThread().isInterrupted()){
         taskCancelledAtShutdown.add(command);
       }
     }
   });
 }

public List<Runnable> getCancelledTask(){
   if(! executorService.isTerminated()){
     throw new IllegalStateException("executorService is not terminated");
   }
   return new ArrayList<>(taskCancelledAtShutdown);
 }
}

上面的例子中我们构建了一个新的ExecutorService,他传入一个ExecutorService,并对其进行封装。

我们重写了execute方法,在执行完毕判断该任务是否被中断,如果被中断则将其添加到CancelledTask列表中。

并提供一个getCancelledTask方法来返回未执行完毕的任务。

我们看下怎么使用:


 public void useShutdownNow() throws InterruptedException {
   TrackingExecutor trackingExecutor=new TrackingExecutor(Executors.newCachedThreadPool());

Runnable runnableTask = () -> {
     try {
       TimeUnit.MILLISECONDS.sleep(300);
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
   };

trackingExecutor.submit(runnableTask);
   List<Runnable> notrunList=trackingExecutor.shutdownNow();
   if(trackingExecutor.awaitTermination(800, TimeUnit.SECONDS)){
     List<Runnable> runButCancelledList= trackingExecutor.getCancelledTask();
   }
 }

trackingExecutor.shutdownNow()返回的是未执行的任务。而trackingExecutor.getCancelledTask()返回的是被取消的任务。

上面的任务其实还有一个缺点,因为我们在存储被取消的任务列表的额时候taskCancelledAtShutdown.add(command),因为之前的判断不是原子操作,则可能会产生误报。

本文的例子请参考https://github.com/ddean2009/learn-java-concurrency/tree/master/ExecutorServiceShutdown

来源:https://segmentfault.com/a/1190000022297727

标签:Java,ExecutorService,线程
0
投稿

猜你喜欢

  • Flutter学习之实现自定义themes详解

    2022-04-17 17:20:49
  • java数字转汉字工具类详解

    2023-04-28 02:00:26
  • Android实现图像切换器

    2023-11-27 00:45:41
  • Spring Security 实现短信验证码登录功能

    2022-11-02 19:39:30
  • Spring Boot2.0中SpringWebContext找不到无法使用的解决方法

    2023-05-26 02:37:01
  • Android 使用gradle打包Assets目录的案例

    2023-08-05 22:29:45
  • C语言实现矩阵翻转(上下翻转、左右翻转)

    2023-10-24 22:42:36
  • IDEA中已配置阿里镜像但maven无法下载jar包的问题及解决方法

    2021-11-09 11:06:53
  • SpringBoot实现过滤器拦截器的耗时对比

    2022-04-12 00:45:04
  • Java动态 代理的应用详解

    2023-11-25 08:15:24
  • Android基于ViewPager+Fragment实现左右滑屏效果的方法

    2023-11-16 10:50:38
  • ASP.NET MVC 5使用X.PagedList.Mvc进行分页教程(PagedList.Mvc)

    2023-09-23 08:02:41
  • spring Boot打包部署到远程服务器的tomcat中

    2023-01-14 21:45:28
  • 在AndroidManifest.xml中uses-sdk内属性意思

    2021-10-08 17:16:09
  • java自带的MessageDigest实现文本的md5加密算法

    2023-10-08 03:35:29
  • java语言基础之标识符和命名规则详解

    2023-04-21 16:50:18
  • Android巧用ActionBar实现下拉式导航

    2023-12-02 04:00:59
  • SpringBoot security安全认证登录的实现方法

    2021-05-30 08:09:56
  • 详解Android中Handler的使用方法

    2023-05-03 06:35:30
  • Android源码学习之工厂方法模式应用及优势介绍

    2023-01-24 06:43:36
  • asp之家 软件编程 m.aspxhome.com