一、如何正确的停止线程
使用interrupt来通知,而不是强制。
interrupt,即中断,需要停止线程时,需要另外一个线程向该线程通知你该中断了,而何时中断,停不停止,是由该线程自己决定的,外部并没有方法直接操作它。
线程何时会停止:
- run()方法中的代码都已经执行完毕了。
- 线程进行业务逻辑处理时抛出异常了。
二、使用interrupt停止线程
1.普通情况下停止线程
先尝试使用thread.interrupt()中断该线程。
/**
* 普通情况下停止线程
*/
public class StopThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Work());
thread.start();
// 线程启动后1s,通知中断
Thread.sleep(1000);
thread.interrupt();
}
}
// 任务:打印出小于999999999的所有1000的倍数的数
class Work implements Runnable{
@Override
public void run() {
for(int num=0; num < 999999999; num ++){
if(num % 1000 == 0){
System.out.println(num);
}
}
System.out.println("任务完成");
}
}
发现即使调用了thread.interrupt(),线程并没有中断。因为线程中没有对这个中断进行响应,需要在线程中添加一些响应中断的代码:
// 任务:打印出小于999999999的所有1000的倍数的数
class Work implements Runnable{
@Override
public void run() {
for(int num=0; num < 999999999; num ++){
// 判断中断
if(Thread.currentThread().isInterrupted()){
break;
}
if(num % 1000 == 0){
System.out.println(num);
}
}
System.out.println("任务完成");
}
}
2.在阻塞的情况下停止线程
线程在sleep阻塞时,收到主线程发来的中断通知:
/**
* 线程中有sleep阻塞的情况下停止线程
*/
public class StopThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Work());
thread.start();
// 线程启动后1s,通知中断
Thread.sleep(500);
thread.interrupt();
}
}
// 任务:打印出小于300的数
class Work implements Runnable{
@Override
public void run() {
for(int num=0; num < 300; num ++){
// 判断中断
if(Thread.currentThread().isInterrupted()){
break;
}
System.out.println(num);
}
// 阻塞等待其他业务逻辑
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务完成");
}
}
会发现抛出了异常,即sleep时收到中断
3.在每次迭代后都阻塞的情况下停止线程
每次迭代都有sleep阻塞,而阻塞的特点就是它本身就能响应中断而抛出异常去停止线程,这种情况下我们就不需要手动去写响应中断的代码了。
/**
* 线程中每次循环都会有sleep阻塞的情况下停止线程
*/
public class StopThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Work());
thread.start();
// 线程启动后1s,通知中断
Thread.sleep(2000);
thread.interrupt();
}
}
// 任务:打印出小于10000的数
class Work implements Runnable{
@Override
public void run() {
try {
for(int num=0; num < 10000; num ++){
System.out.println(num);
Thread.sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务完成");
}
}
4.sleep会清除中断标志的问题
如果 try{ sleep }catch 放在循环内,当sleep响应中断后,会清除中断标志位,所以即使我们使用Thread.currentThread().isInterrupted()来手动响应中断,也不会停止线程。
// 任务:打印出小于10000的数
class Work implements Runnable{
@Override
public void run() {
for(int num=0; num < 10000; num ++){
// 手动响应
if(Thread.currentThread().isInterrupted()){
break;
}
System.out.println(num);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("任务完成");
}
}