一块儿来学多线程-优雅关闭线程

Java中原来在Thread中提供了 stop()方法来终止线程,但这个方法是不安全的,因此通常不建议使用。文本将介绍两种能够优雅的终止线程的方式...java

第一种

在JAVA Java多线程模式》中有一种叫 Two-PhaseTermination(两步终止)的模式能够优雅的终止线程,这种模式采用了两个步骤来终止线程,因此叫 两步终止模式git

  • 先将执行标志位 isShutdown 设为 false,使工做中的线程转变为 终止处理中的状态安全

  • 真正去执行终止操做,这样的作法能够保证线程的安全性、生命性和响应性。微信

  
    
  
  
  
   
   
            
   
   
  1. 多线程

  2. ide

  3. 测试

  4. flex

  5. this

  6. 编码

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接收到关闭通知......打断正在工做的线程......销毁......
  • 安全性:不会在线程正在执行关键区域 --CriticalSection的时候忽然结束掉

  • 生命性:必定会进行终止处理, 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(longmills),监听工做状况 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打断正在工做的线程......

- 说点什么

微信公众号: battcn(欢迎调戏)

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

  • 我的QQ:1837307557


本文分享自微信公众号 - battcn(battcn)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索