Java中原来在Thread中提供了
stop()方法
来终止线程,但这个方法是不安全的,所以一般不建议使用。文本将介绍两种可以优雅的终止线程的方式...
<!-- more -->
第一种
在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
打断正在工作的线程......
- 说点什么
- 个人QQ:1837307557
- battcn开源群(适合新手):391619659
微信公众号:battcn
(欢迎调戏)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。