Java Thread 中断
概念
Java的中断是一种协作机制,也就是说通过中断并不能直接中断另外一个线程,而需要被中断的线程自己处理中断。
在Java的中断模型中,每个线程都有一个boolean标识,代表着是否有中断请求(该请求可以来自所有线程,包括被中断的线程本身)。例如,当线程t1想中断线程t2,只需要在线程t1中将线程t2对象的中断标识置为true,然后线程2可以选择在合适的时候处理该中断请求,甚至可以不理会该请求,就像这个线程没有被中断一样。
中断方法
方法名 | 介绍 |
---|---|
void interrupt() | 中断线程,设置线程的中断位true |
boolean isInterrupted() | 检查线程的中断标记位,true-中断状态, false-非中断状态 |
static boolean interrupted() | 静态方法,返回当前线程的中断标记位,同时清除中断标记,改为false。比如当前线程已中断,调用interrupted(),返回true, 同时将当前线程的中断标记位改为false, 再次调用interrupted(),会发现返回false |
中断Sleep 、wait、join方法,会清楚中断标记,不能通过中断标记处理逻辑
阻塞方法sleep响应中断,抛出InterruptedException,同时清除中断标记位为false。
/**
* 在中断sleep,wait,join的线程时,会清除中断标记,无法获取中断标记
* 线程在sleep时被中断,被中断后会抛出InterruptedException异常,并且会清除中断标记,无法获取中断标记
* @throws InterruptedException e
*/
public void testSleepThread() throws InterruptedException {
Thread sleepThread = new Thread(() -> {
int i = 100;
boolean stop = false;
while (i-- > 0 && !stop) {
log.debug("{} status: [{}]",Thread.currentThread().getName(), Thread.currentThread().isInterrupted());
log.info("线程执行中");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log.info("线程被中断");
stop = Thread.currentThread().isInterrupted();
e.printStackTrace();
log.debug("stop status: [{}]", stop);
}
}
}, "sleepThread");
sleepThread.start();
Thread.sleep(2000);
sleepThread.interrupt();
Thread.sleep(2000);
log.debug("{} status: [{}]",sleepThread.getName(), sleepThread.isInterrupted());
Thread.sleep(2000);
}
正常中断,可以处理中断逻辑
/**
* 正常被中断的线程,可以获取中断标记,获取中断标记后处理中断逻辑
* @throws InterruptedException e
*/
public void testNormalInterrupt() throws InterruptedException {
Thread sleepThread = new Thread(() -> {
int i = 100000;
boolean stop = false;
while (i-- > 0 && !stop) {
stop = Thread.currentThread().isInterrupted();
log.info("{} status: [{}]",Thread.currentThread().getName(), stop);
log.info("线程执行中");
if (stop) {
log.info("线程被中断,处理中断逻辑。。。");
}
}
}, "normalInterruptThread");
sleepThread.start();
Thread.sleep(3);
sleepThread.interrupt();
log.debug("{} status: [{}]",sleepThread.getName(), sleepThread.isInterrupted());
Thread.sleep(2000);
}
使用LockSupport.park() 阻塞线程,使用unpark中断唤醒被Park的线程,与interrupt()不冲突,可继续使用interrupt()打断线程
/**
* 使用LockSupport.park() 阻塞线程,使用unpark中断唤醒被Park的线程,与interrupt()不冲突,可继续使用interrupt()打断线程
* @throws InterruptedException
*/
public void testParkThread() throws InterruptedException {
Thread parkThread = new Thread(() -> {
log.info("interrupt status: [{}]", Thread.currentThread().isInterrupted());
log.info("parkThread park前,等待线程被打断.....");
LockSupport.park();
log.info("parkThread 被打断park后.....");
log.info("interrupt status: [{}]", Thread.currentThread().isInterrupted());
boolean fla = Thread.currentThread().isInterrupted();
while (!fla){
fla = Thread.currentThread().isInterrupted();
log.info("循环中断标志位[{}]",fla);
if (fla){
log.info("触发中断异常,处理中断逻辑.....");
}
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
log.info("parkThread sleep 5000后");
}, "parkThread");
parkThread.start();
Thread.sleep(1000);
log.info("parkThread unpark前.....");
LockSupport.unpark(parkThread);
log.info("parkThread unpark后.....");
Thread.sleep(1);
parkThread.interrupt();
Thread.sleep(5000);
}