资讯专栏INFORMATION COLUMN

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

曹金海 / 2315人阅读

摘要:文本将介绍两种可以优雅的终止线程的方式第一种在多线程模式中有一种叫两步终止的模式可以优雅的终止线程,这种模式采用了两个步骤来终止线程,所以叫两步终止模式。

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(),保证即使线程处于sleepwait状态也可以被立即终止

响应性:将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

个人QQ:1837307557

battcn开源群(适合新手):391619659

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67630.html

相关文章

  • 一起并发编程 - 钩子函数(shutdownHook)

    摘要:在退出时执行必要的挽救措施。在这种情况下,一旦被提供,等待一个进程终止指定的时间。如果进程在该时间限制内没有终止,则通过发出或中的对等方强制终止进程。所以有可能这是在中途执行时发生的。 shutdownHook是一种特殊的结构,它允许开发人员插入JVM关闭时执行的一段代码。这种情况在我们需要做特殊清理操作的情况下很有用 用途 在Jboss,Jetty等容器中都可以看到shutdown...

    qpal 评论0 收藏0
  • 一起并发编程 - 简易线程池实现

    摘要:并且,线程池在某些情况下还能动态调整工作线程的数量,以平衡资源消耗和工作效率。同时线程池还提供了对池中工作线程进行统一的管理的相关方法。 开发中经常会遇到各种池(如:连接池,线程池),它们的作用就是为了提高性能及减少开销,在JDK1.5以后的java.util.concurrent包中内置了很多不同使用场景的线程池,为了更好的理解它们,自己手写一个线程池,加深印象。 概述 1.什么是...

    Harriet666 评论0 收藏0
  • 一起并发编程 - 处理异常中止的线程

    摘要:在之前,不能为线程单独设置或指定一个默认的,为了设置,需要继承并覆写方法。幸运的是后线程提供了一个方法,用来捕获并处理因线程中抛出的未知异常,以避免程序终止。 在单线程的开发过程中,通常采用try-catch的方式进行异常捕获,但是这种方式在多线程环境中会显得无能为力,而且还有可能导致一些问题的出现,比如发生异常的时候不能及时回收系统资源,或者无法及时关闭当前的连接... 概述 Ja...

    zacklee 评论0 收藏0
  • 一起并发编程 - 利用观察者模式监听线程状态

    摘要:在前面的文章中介绍过观察者模式及并发编程的基础知识,为了让大家更好的了解观察者模式故而特意写了这篇番外概述在多线程下我们需要知道当前执行线程的状态是什么比如运行,关闭,异常等状态的通知,而且不仅仅是更新当前页面。 在前面的文章中介绍过 观察者模式 及 并发编程的基础知识,为了让大家更好的了解观察者模式故而特意写了这篇番外.. 概述 在Java多线程下,我们需要知道当前执行线程的状态是...

    Juven 评论0 收藏0
  • 一起并发编程 - 线程Join分析

    摘要:当时,会进入循环,系统会判断主线程是否处于活跃状态,如果处于活跃状态,主线程就会不停的等待。 由于前段时间比较忙,线程这快学习停滞了,只能利用周日的时间来写写博客了,多线程Join方法的作用就是把指定的线程加入到当前线程,让主线程等待子线程结束之后才能继续运行,从而完成同步操作 介绍 join() 的作用:让主线程等待子线程结束之后才能继续运行,首先先来看下以采集为案例的代码,统计采...

    happen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<