1、一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。因此,Java提供了一种用于停止线程的协商机制--中断,也即中断标识协商机制。
中断只是一种协作协商机制,Java没有给中断增加任何语法,中断的过程完全需要程序员自己实现。它与stop最大的区别是:stop是由系统强制终止线程,而线程中断则给目标线程发送一个中断信号,如果目标线程没有接受线程中断的信号并结束线程,线程则不会终止,具体是否退出或者执行其他逻辑由目标线程决定。
2、中断的相关方法
1)public void interrupt(): 仅仅是设置线程的中断状态为true,发起一个协商而不会立刻停止线程。
2)public static boolean interrupted():判断线程是否被中断,并清除当前中断状态这个方法做了两件事:
a.返回当前线程的中断状态。
b.将当前线程的中断状态设为false。
3)public boolean isInterrupted():通过检查中断标志位,判断当前线程是否被中断。
3、使用中断标识停止线程
中断机制就是子啊需要中断的线程中不断监听中断状态,一旦发生中断,就执行相应的中断处理业务逻辑stop线程。
3.1通过volatile变量实现
volatile保证了可见性,t2线程修改了标志位后能马上被t1线程看到
import java.util.concurrent.TimeUnit;
public class InterruptDemo1 {
/**
* 设置中断标识
*/
private static volatile boolean isStop = false;
public static void main(String[] args) throws InterruptedException{
new Thread(new Runnable() {
@Override
public void run() {
//通过while循环不断监听中断状态
while (true){
//如果这个标志位被其他线程改为true
if (isStop){
System.out.println(Thread.currentThread().getName() + "\t isStop被修改为true");
break;
}
//如果没有停止,那就一直打印
System.out.println("t1 ----------------Hello volatile");
}
}
},"t1").start();
TimeUnit.MICROSECONDS.sleep(20);
new Thread(()->{
isStop = true;
},"t2").start();
}
}
3.2通过AtomicBoolean实现
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public class InterruptDemo2 {
//设置中断标志
private static AtomicBoolean atomicBoolean = new AtomicBoolean(false);
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
//通过while循环不断监听中断状态
while (true){
//如果这个标志位被其他线程改为true
if (atomicBoolean.get()){
System.out.println(Thread.currentThread().getName() + "\t isStop被修改为true");
break;
}
//如果没停止,那就一直打印
System.out.println("t1-----Hello AtomicBoolean");
}
},"t1").start();
TimeUnit.MICROSECONDS.sleep(20);
new Thread(()->{
atomicBoolean.set(true);
},"t2").start();
}
}
3.3 通过Thread类自带的中断api实现
默认的中断标志位是false,然后通过Thread类自带的interrupted方法被改为true。
import java.util.concurrent.TimeUnit;
public class InterruptDemo3 {
public static void main(String[] args) throws InterruptedException{
Thread t1 = new Thread(()->{
while (true){
//通过while循环不断监听中断状态
if (Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread().getName()+"\t isInterrupted()被修改为true,程序终止");
break;
}
//如果没有停止,那就一直打印
System.out.println("t1---Hello interrupt");
}
},"t1");
t1.start();
TimeUnit.MICROSECONDS.sleep(20);
new Thread(()->{
//把t1中断
t1.interrupt();
},"t2").start();
}
}
4、API源码分析
实例方法interrupt(),没有返回值:仅仅是设置一个中断标志位。
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
调用底层的C语言
private native void interrupt0();
实例方法isInterrupted,返回布尔值。
public boolean isInterrupted(){
return interrupted;
}
private volatile boolean interrupted; //也调用了C语言
5、总结
当对一个线程调用interrupt()时:
a.如果线程处于正常活动状态,那么会将该线程的中断状态标志设置为true,仅此而已,被设置中断状态的线程将继续正常运行,不受影响。所以,interrupt()并不能真正的中断状态,需要被调用的线程自己进行配合才行。
b.如果线程处于被阻塞状态(例如处于sleep、wait、join等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,并抛出一个interruptedException异常。