目录
前言
这个问题是一个高频的面试题
而且在印象中是由stop方法执行或者终端中的kill杀死
但是这些方法直接简单粗暴,很不安全,而且也不推广
不使用stop的方法
之所以不安全不推广是因为:
- stop方法不管线程逻辑是否完整,都会终止当前正在运行的线程
- 会破坏其原子逻辑(多线程加了锁之解决资源共享,但是stop会将其所有锁丢弃,造成混乱)
补充如果优雅的关闭线程池:(比如ThreadPoolExecutor类)
可以通过shutdown方法逐步关闭池中的线程(温和安全)
- shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
- shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
1. volatile关键字
使用自定义的标志位决定线程的执行情况
具体思路大致如下:设置一个 父线程 的状态变量,以其影响其子线程即可
public class test extends Thread {
//标识线程是否结束
public static boolean thread_stop = true;
public void stopThread() {
thread_stop = false;
}
public static void main(String[] args) {
test t = new test();
t.start();
System.out.println("Father Thread Start");
try {
//先让线程跑起来
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
//结束线程
//将其状态变量直接改为false
//thread_stop = false;
//调用方法改为false(与状态变量直接修改 一个道理)
t.stopThread();
System.out.println("Father Thread end");
}
@Override
public void run() {
while (thread_stop) {
System.out.println("Child Thread Start");
}
System.out.println("Child Thread end");
}
}
但是网上说不加volatile是停不下来的,其实是可以停下来的
只不过
加了volatile有几个好处:
- volatile可以保证状态变量为系统内存值而不是缓存里值(避免值不一致)
- volatile 关键字能够是该变量对其他线程“可见”,即当主线程修改变量并刷新到主内存后,会让其他线程去主内存中读取该变量。当然,volatile并不能保证线程的安全性
具体加在状态变量中的位置如下:
//标识线程是否结束
public static volatile boolean thread_stop = true;
之后具体完整的输出为:
具体完整的输出为:
Father Thread start
Child Thread Start
Child Thread Start
。。。
。。。
Child Thread Start
Child Thread Start
Father Thread end
Child Thread end
2. intrrrupt()方法
不能终止一个正在执行着的线程,它只是修改中断标志而已
这个中断方法可以将阻塞的线程唤醒过来, 但是将非阻塞的线程中断(中断的同时,会抛出一个异常InterruptedException)
public class test extends Thread {
public static void main(String[] args) {
test t = new test();
t.start();
System.out.println("Father Thread Start");
try {
//先让线程跑起来
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
//结束线程
t.interrupt();
System.out.println("Father Thread end");
}
@Override
public void run() {
//分配线程的中断状态,并且此状态可以由interrupted()方法生成
while (!Thread.interrupted()) {
System.out.println("Child Thread Start");
}
System.out.println("Child Thread end");
}
}
执行结果截图:
具体完整的输出为:
Father Thread start
Child Thread Start
Child Thread Start
。。。
。。。
Child Thread Start
Child Thread Start
Father Thread end
Child Thread end