要弄明白 interrupt,首先要了解以下几点:
-
Java中线程间是协作式,而非抢占式. 调用一个线程的interrupt() 方法中断一个线程,并不是强行关闭这个线程,只是跟这个线程打个招呼,将线程的中断标志位置为true,线程是否中断,由线程本身决定。
-
isInterrupted() 判定当前线程是否处于中断状态。
-
静态方法 interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为 true。
-
如果方法里如果抛出中断异常 InterruptedException,则线程的中断标志位会被复位成false,如果确实是需要中断线程,要求我们自己在catch语句块里再次调用interrupt()。
-
Java 中所有的阻塞方法都会抛出 InterruptedException
代码演示1和4
Java中线程间是协作式,而非抢占式
public class EndThread {
private static class UseThread extends Thread{
public UseThread(String name) {
super(name);
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
while(true) {
System.out.println(threadName+" is run!");
}
//System.out.println(threadName+" interrput flag is "+isInterrupted());
}
}
public static void main(String[] args) throws InterruptedException {
Thread endThread = new UseThread("endThread");
endThread.start();
Thread.sleep(20);
endThread.interrupt();
}
}
运行结果:
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
endThread is run!
...
endThread 一直在运行,主线程调用 interrupt() 方法并没有使 endThread 真正中断
public class EndRunnable {
private static class UseRunnable implements Runnable{
@Override
public void run() {
String threadName = Thread.currentThread().getName();
while(Thread.currentThread().isInterrupted()) {
//如果真发生中断后,这行代码不会执行了
System.out.println(threadName+" is run!");
}
System.out.println(threadName+" interrupt flag is " +Thread.currentThread().isInterrupted());
}
}
public static void main(String[] args) throws InterruptedException {
UseRunnable useRunnable = new UseRunnable();
Thread endThread = new Thread(useRunnable,"endThread");
endThread.start();
Thread.sleep(20);
endThread.interrupt();
}
}
运行结果:
endThread interrupt flag is false
通过 while(Thread.currentThread().isInterrupted()) 这种方式来控制循环能真正实现 interrupt
由上面两个例子论证了Java中线程间是协作式,而非抢占式
如果方法里如果抛出中断异常 InterruptedException,则线程的中断标志位会被复位成false
public class HasInterruptException {
private static SimpleDateFormat formater
= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss_SSS");
private static class UseThread extends Thread{
public UseThread(String name) {
super(name);
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
while(!isInterrupted()) {
try {
System.out.println("UseThread:"+formater.format(new Date()));
Thread.sleep(3000);
} catch (InterruptedException e) {
System.out.println(threadName + " catch interrput flag is "
+ isInterrupted() + " at "
+ (formater.format(new Date())));
//方法里如果抛出InterruptedException,线程的中断标志位会被复位成false,
// 如果确实是需要中断线程,要求我们自己在catch语句块里再次调用interrupt()。
interrupt();
e.printStackTrace();
}
System.out.println(threadName);
}
System.out.println(threadName+" interrput flag is " +isInterrupted());
}
}
public static void main(String[] args) throws InterruptedException {
Thread endThread = new UseThread("HasInterrputEx");
endThread.start();
System.out.println("Main:"+formater.format(new Date()));
Thread.sleep(800);
System.out.println("Main begin interrupt thread:"+formater.format(new Date()));
endThread.interrupt();
}
}
运行结果:
UseThread:2019-09-10 15:06:57_995
Main:2019-09-10 15:06:57_995
Main begin interrupt thread:2019-09-10 15:06:58_795
HasInterrputEx catch interrput flag is false at 2019-09-10 15:06:58_795
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.xiangxue.ch1.safeend.HasInterrputException$UseThread.run(HasInterrputException.java:28)
HasInterrputEx
HasInterrputEx interrput flag is true