程序猿学社的GitHub,欢迎Star
https://github.com/ITfqyd/cxyxs
本文已记录到github,形成对应专题。
前言
最近,有一个网友,在某技术群里,提出一个问题,线程怎么停止,有什么好的方法,群里有不少人的回答,都是直接调用stop方法。我的回答是这样的,各位可以帮我看看对不对。因为停止线程也没有我们想象中的那么简单。
方法一:stop方法
- 通过查看Thread类的源码,我们可以发现stop方法上面有 @Deprecated注解,这个方法已经out。
- stop方法会导致代码逻辑不完整,他收到停止命令后,会立即停止。
- stop方法会破坏原子逻辑。
过时
@Deprecated注解表示该方法是过时方法。
代码逻辑没有运行完,就退出
package com.cxyxs.thread.nine;
/**
* Description:验证业务逻辑
* 转发请注明来源 程序猿学社 - https://ithub.blog.csdn.net/
* Author: 程序猿学社
* Date: 2020/2/27 10:01
* Modified By:
*/
public class LogicIncomplete implements Runnable{
@Override
public void run() {
try {
System.out.println("正在运行代码中");
Thread.sleep(1000);
System.out.println("关键代码!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
LogicIncomplete logic = new LogicIncomplete();
Thread thread = new Thread(logic);
thread.start();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.stop();
}
}
- 子线程调用stop后,立马就停止,因为该进程内,没有用户线程,所以整个程序也自动退出了。
- 按照正常的退出逻辑,应该会输出"关键代码"这段话。例如,定时把15分钟的图片,10秒一张,合成一张图片,流程是先把图片打上水印,放到某个临时文件夹,再合成视频,再删除临时文件,如果中途调用stop方法,可能会导致本地有很多临时文件。
- 这种方式因为不安全,太粗暴,所以,不建议使用。
方法二:通过标识位,停止线程
package com.cxyxs.thread.nine;
/**
* Description:通过设置标志位,停止线程
* 转发请注明来源 程序猿学社 - https://ithub.blog.csdn.net/
* Author: 程序猿学社
* Date: 2020/2/27 14:32
* Modified By:
*/
public class FlagThread implements Runnable{
private boolean flag = true;
@Override
public void run() {
int count=1;
while (flag){
System.out.println("程序猿学社:"+count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
System.out.println("逻辑已跑完!");
}
}
public static void main(String[] args) throws InterruptedException {
FlagThread flagThread = new FlagThread();
Thread thread = new Thread(flagThread);
thread.start();
Thread.sleep(5000);
flagThread.flag = false;
}
}
- 主要逻辑,有两个线程,main线程和我们自定义的线程,main线程延迟5秒后,直接通过标识位,把自定义的那个线程停止。
- 通过观察结果,我们可以发现,通过这种方式停止,他会保证run方法里面的业务逻辑都跑完。
- 使用该方面一定要给出终止条件,不然开销成本不小。
- 如果这个线程,需要一直运行,最好,还是适当的让出资源。
方法三:通过标识位+异常处理结束线程
package com.cxyxs.thread.nine;
/**
* Description:转发请注明来源 程序猿学社 - https://ithub.blog.csdn.net/
* Author: 程序猿学社
* Date: 2020/2/27 14:55
* Modified By:
*/
public class InterruptThread implements Runnable{
private static boolean flag = true;
@Override
public void run() {
int count=1;
while (flag){
try {
System.out.println("程序猿学社:"+count);
Thread.sleep(1000);
} catch (InterruptedException e) {
this.flag = false;
e.printStackTrace();
}finally {
count++;
System.out.println("逻辑已跑完!");
}
}
}
public static void main(String[] args) throws InterruptedException {
InterruptThread interruptThread = new InterruptThread();
Thread thread = new Thread(interruptThread);
thread.start();
Thread.sleep(5000);
thread.interrupt();
}
}
- 通过测试,我们可以发现,通过异常+interrupt方式,我们可以顺利的结束线程,也不会存在不安全的问题。
- interrupt是无法停止线程的,只是做个标记状态,具体他的使用方法,我们后续再一步一步的分析他的源码。
**总结:**创建线程,建议使用线程池的方式,里面shutdown方法可以停止线程。