为什么使用interrupt()中断而放弃了stop()方法终止线程;
interrupt方法是一个让我们程序员优雅的中断线程的方法,
因为JVM不推荐直接停止一个线程,直接停止线程可能导致资源没有及时释放,会产生不安全的问题—jvm一定要让一个线程执行完成!
jvm一定要让一个线程执行完成 —假设现在线程在阻塞–interrupt可以解阻塞—继续往下执行
jvm一定要让一个线程执行完成 —假设线程是while (!flag)–flag=th.isInterrupted() --false
案例:
/**
* 这里需要注意一下,try catch到InterruptedException e异常时,中断信号会被抹除,
* 所以th.isInterrupted()如果执行在catch异常前,则isInterrupted为true,可以正常退出,否则中断信号抹除后,
* isInterrupted得到的值为false,故还是死循环
*/
public class ThreadInterruptLuban {
static Thread th=new Thread();
public static boolean flag=false;
public static void main(String[] args) {
th = new Thread(() -> {
while (!flag) {
try {
System.out.println("im in while true");
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("-------"+th.isInterrupted());
}
System.out.println("-----next");
System.out.println(th.isInterrupted());
}
});
th.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
th.interrupt();
flag=th.isInterrupted();
System.out.println("flag : "+flag);
}
}
一、interrupt
当当前线程被进入阻塞状态,若另外的一个线程调用被阻塞的interrupt方法,则会打断这种阻塞,因此这种方法有时会被称为可中断方法,记住,打断一个线程并不等于该线程的生命周期结束,仅仅是打断了当前线程的阻塞状态。
一但线程在阻塞的情况下被打断,都会抛出InterruptedException的异常,这个异常就像一个signal(信号)一样通知当前线程被打断了。
实例:
/**
* Created by yd on 2019/5/30.
*/
public class ThreadInterrupt {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread() {
@Override
public void run() {
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
System.out.println("Oh, I am be interrupted");
}
}
};
thread.start();
TimeUnit.MILLISECONDS.sleep(2);
thread.interrupt();
}
}
运行结果:
Oh, I am be interrupted
二、isInterrupted()
isInterrupted主要判断当前线程是否被中断,该方法仅是对interrupt标识的一个判断,并不会影响标识发生任何改变!
案例:
public class ThreadidInterrupted {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread() {
@Override
public void run() {
while (true) {
//do nothing,just empty loop
}
}
};
thread.start();
TimeUnit.MILLISECONDS.sleep(2);
System.out.printf("Thread is interrupted ? %s\n", thread.isInterrupted());
thread.interrupt();
System.out.printf("Thread is interrupted ? %s\n", thread.isInterrupted());
}
}
运行结果:
Thread is interrupted ? false
Thread is interrupted ? true
请注意:
可中断方法捕获到了中断信号(signal)之后,也就是捕获了InterruptedException异常后会擦除掉interrupt标识。
由于在run方法中使用了sleep这个可中断方法,它会捕获到中断信号,并且会擦除interrupt标识,因此程序的执行结果都会是false;
案例2:
public class ThreadidInterrupted2 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread() {
@Override
public void run() {
while (true) {
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
System.out.printf("I am be interrupted ? %s\n", isInterrupted());
}
}
}
};
thread.setDaemon(true);
thread.start();
TimeUnit.MILLISECONDS.sleep(2);
System.out.printf("Thread is interrupted ? %s\n", thread.isInterrupted());
thread.interrupt();
TimeUnit.MILLISECONDS.sleep(2);
System.out.printf("Thread is interrupted ? %s\n", thread.isInterrupted());
}
}
运行结果:
Thread is interrupted ? false
I am be interrupted ? false
Thread is interrupted ? false
其实这也不难理解,可中断方法捕获到了中断信号之后,为了不影响线程中其他方法的执行,将线程的interrupt标识复位是一种合理的设计。
三、interrupted()方法
interrupted是一个静态方法,虽然其也用于判断当前线程是否被中断,但是它和成员方法isInterrupted有很大区别,调用该方法会直接擦除掉线程的interrupt标识,需要注意的是,如果当前线程被打断了,那么第一次调用interrupted方法会返回true,并且立即擦除了interrupt标识;第二次包括以后的调用永远都会返回false,除非在此期间线程又一次被打断。
案例:
public class ThreadidInterrupted3 {
public static void main(String[] args) throws InterruptedException {
//1、判断当前线程是否被中断
System.out.println("main is interrupted ? " + Thread.interrupted());
//2、中断当前线程
Thread.currentThread().interrupt();
//3、判断当前线程是否被已经中断
System.out.println("main is isInterrupted ? " + Thread.currentThread().isInterrupted());
//线程发生中断,第一次调用,返回true,并擦除标识
System.out.println("main is interrupted ? " + Thread.interrupted());
//第二次false
System.out.println("main is interrupted ? " + Thread.interrupted());
try {
//4、当前线程 执行可中断
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
//因为interrupted()擦除了中断标识,所以无法进入捕获异常处理
//5、捕获中断信号
System.out.printf("I will be interrupted still.");
}
}
}
运行结果:
main is interrupted ? false
main is isInterrupted ? true
main is interrupted ? true
main is interrupted ? false
线程中断时,调用interrupted会立即擦除了interrupt标识,所以无法进入捕获InterruptedException异常的处理逻辑中!