使用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

更多内容请参考http://www.flydean.com/java-shutdown-executorservice/

使用ExecutorService来停止线程服务的更多相关文章

  1. Java 创建线程/停止线程

    继承 Thread 类 class MyThread1 extends Thread{ @Override public void run(){ System.out.println("继承 ...

  2. 停止运行ExecutorService中的线程

    while(true){ try { sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch bloc ...

  3. 不停止MySQL服务增加从库的两种方式

    不停止MySQL服务增加从库的两种方式 转载自:http://lizhenliang.blog.51cto.com/7876557/1669829 现在生产环境MySQL数据库是一主一从,由于业务量访 ...

  4. 不停止MySQL服务增加从库的两种方式【转载】

    现在生产环境MySQL数据库是一主一从,由于业务量访问不断增大,故再增加一台从库.前提是不能影响线上业务使用,也就是说不能重启MySQL服务,为了避免出现其他情况,选择在网站访问量低峰期时间段操作. ...

  5. Mac下启动和停止Mysql服务

    方法1. 启动Mysql服务   sudo /Library/StartupItems/MySQLCOM/MySQLCOM start   停止Mysql服务   sudo /Library/Star ...

  6. (转)不停止Nginx服务的情况下平滑变更Nginx配置

    在不停止Nginx服务的情况下平滑变更Nginx配置 1.修改/usr/local/webserver/nginx/conf/nginx.conf配置文件后,请执行以下命令检查配置文件是否正确: /u ...

  7. PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束

    PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束 ExecutorService并没有提供什么 isDone()或者isComplete()之类的方法. 作者Atti ...

  8. Linux Systemd——在RHEL/CentOS 7中启动/停止/重启服务

    RHEL/CentOS 7.0中一个最主要的改变,就是切换到了systemd.它用于替代红帽企业版Linux前任版本中的SysV和Upstart,对系统和服务进行管理.systemd兼容SysV和Li ...

  9. 启动和启动和停止MySQL服务停止MySQL服务

    1.  启动MySQL服务 启动MySQL服务的命令为: /etc/init.d/mysqld start 命令执行后如图7-5所示,表示启动MySQL服务成功.   (点击查看大图)图7-5  启动 ...

随机推荐

  1. python常用模块 以及第三方导入

    python常用模块 1模块的分类 标准模块(内置模块)( 标准库 )300 第三方模块 18万 pip install 直接通过pip安装 软件一般会被自动安装你python安装目录的这个子目录里 ...

  2. P1250 种树(差分约束 / 贪心)

    题目描述 一条街的一边有几座房子.因为环保原因居民想要在路边种些树.路边的地区被分割成块,并被编号成1-N.每个部分为一个单位尺寸大小并最多可种一棵树.每个居民想在门前种些树并指定了三个号码B,E,T ...

  3. 字符串学习笔记(三)---- StringBuilder

    一.前言 StringBuilder是jdk1.5后出现的,而StringBuffer是jdk1.0就出现了,并且在功能上俩者并无太大区别.但为什么后来要添加一个StringBuilder呢?这是为了 ...

  4. 【Linux】Linux(一)Linux常用命令

    一 命令行提示符 1.[root@localhost ~]# 当前登录用户@主机名:当前所在目录$ # 超级用户 $  普通用户 当前所在目录:~ 用户家目录 管理员 /root 普通用户 /home ...

  5. django-生产和测试环境分离

    django-生产和测试环境分离 在settings.py的同级目录下新建settings的文件夹 在settings文件夹下新建 __init__.py base.py develop.py pro ...

  6. (js描述的)数据结构[栈结构](2)

    (js描述的)数据结构[栈结构](2) 一.什么是栈结构 1.一种受限制的线性结构,这种结构可以基于数组来实现. 2.可以抽象成一个容器,上面的是栈顶,底下的是栈底.所以仅允许对栈顶进行操作, 二.栈 ...

  7. python 入门 之 Json 序列化

    开发网站,离不了Json 但是一般情况,不支持python的其它对象,怎么办? 有办法:Json 序列化!!! 总体来说,需要序列化的数据类型为 字典,类,嵌套类. 下面是我做的一个demo,都包含了 ...

  8. javascript 入门 之select2选择本地数据

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <meta lan ...

  9. Win安装docker

    Windows Docker 安装 win7.win8 系统 win7.win8 等需要利用 docker toolbox 来安装,国内可以使用阿里云的镜像来下载,下载地址:http://mirror ...

  10. bootstrap-table 内容超出鼠标悬浮显示全部

    .table th, .table td { text-align: center; vertical-align: middle !important; } table { width: 100px ...