欢迎光临
我们一直在努力

一起学并发编程-优雅关闭

作者:唐亚峰
来源:https://blog.battcn.com

一起学并发编程-优雅关闭

Java中原来在Thread中提供了stop()方法来终止线程,但这个方法是不安全的,所以一般不建议使用。文本将介绍两种可以优雅的终止线程的方式…

第一种

在JAVA《Java多线程模式》中有一种叫Two-Phase Termination(两步终止)的模式可以优雅的终止线程,这种模式采用了两个步骤来终止线程,所以叫两步终止模式。

  • 先将执行标志位isShutdown 设为false,使工作中的线程转变为终止处理中的状态
  • 真正去执行终止操作,这样的做法可以保证线程的安全性、生命性和响应性。
class Worker extends Thread {
 private volatile boolean isShutdown = true;
 public void shutdown() {
 System.out.println("接收到关闭通知......");
 this.isShutdown = false;
 interrupt();
 }
 @Override
 public void run() {
 while (this.isShutdown) {
 System.out.println("正在工作:" + System.currentTimeMillis());
 try {
 Thread.sleep(1000);
 } catch (InterruptedException e) {
 System.out.println("打断正在工作的线程......");
 }
 }
 System.out.println("销毁......");
 }
}
public class ThreadClose {
 public static void main(String[] args) throws InterruptedException {
 Worker worker = new Worker();
 worker.start();//开始工作
 Thread.sleep(3 * 1000);
 worker.shutdown();//优雅关闭
 }
}

运行日志

正在工作:1505828036769
正在工作:1505828037770
正在工作:1505828038771
接收到关闭通知......
打断正在工作的线程......
销毁......
  • 安全性:不会在线程正在执行关键区域–Critical Section的时候突然结束掉
  • 生命性:一定会进行终止处理,shutdown()中,会调用interrupt(),保证即使线程处于sleep或wait状态也可以被立即终止
  • 响应性:将isShutdown 设为volatile ,能保证线程收到终止请求后,会尽快开始终止处理。

存在的问题:针对没有阻塞的情况:设置标志变量,让线程正常自然死亡,和谐!,但是如果在调用shutdown发生阻塞情况呢?

第二种

在 《多线程第一章》的时候,介绍过守护线程的作用,那么是不是可以通过开启守护线程的方式去监听

功能

1.当工作结束就关闭主线程(主线程销毁守护线程也会跟着一同销毁)

2.如果任务长时间未完成,停止工作任务,减少开销

编码

1.定义主线程与发送的指令

2.在主线程run方法中创建一个守护线程,用来执行我们投递的任务

3.前面已经介绍过join的功能,它可以阻塞主线程,等待子线程完成后主线程继续执行

4.如果join释放后,发送完成指令

private Thread executeService;
private volatile boolean finished = false;
public void execute(Runnable task) {
 executeService = new Thread(() -> {
 Thread runner = new Thread(task);
 runner.setDaemon(true);
 runner.start();
 try {
 runner.join();//前面已经说过join与线程了
 finished = true;
 } catch (InterruptedException e) {
 System.out.println("打断正在工作的线程......");
 }
 });
 executeService.start();
}

5.创建listener(long mills),监听工作情况

6.监听任务是否完成,如果未完成监听当前是否逾期,逾期打断线程结束监听

public void listener(long mills) {
 System.out.println("开启监听......");
 long currentTime = System.currentTimeMillis();
 while (!finished) {
 if ((System.currentTimeMillis() - currentTime) >= mills) {
 System.out.println("工作耗时过长,开始打断...");
 executeService.interrupt();//打断线程
 break;
 }
 try {
 executeService.sleep(100L);//每隔100毫秒检测一次
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
}

7.测试

public static void main(String[] args) {
 WorkerService service = new WorkerService();
 long start = System.currentTimeMillis();
 service.execute(() -> {
 try {
 Thread.sleep(3 * 1000);// TODO 模拟加载数据
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 });
 service.listener(4 * 1000);
 System.out.println("一共耗时:" + (System.currentTimeMillis() - start));
}

listener(4 * 1000) 的运行日志,当任务完成会直接退出,并不会一直占用

开启监听......
一共耗时:3049

listener(2 * 1000) 的运行日志,当任务超时直接打断线程,减少资源占用

开启监听......
工作耗时过长,开始打断...
一共耗时:2050
打断正在工作的线程......

– 说点什么

全文代码:https://gitee.com/battcn/battcn-concurent/tree/master/Chapter1-1/battcn-thread/src/main/java/com/battcn/chapter4

 收藏 (0) 打赏

您可以选择一种方式赞助本站

支付宝扫一扫赞助

微信钱包扫描赞助

未经允许不得转载:英协网 » 一起学并发编程-优雅关闭

分享到: 生成海报
avatar

热门文章

  • 评论 抢沙发

    • QQ号
    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址

    登录

    忘记密码 ?

    切换登录

    注册

    我们将发送一封验证邮件至你的邮箱, 请正确填写以完成账号注册和激活