- 面试不多,难度低,但是容易混淆
- 此处线程的“打断”不是把线程打折腿
- 不是线程的停止与中断
- 名字不好===>容易混淆
线程打断的3个方法
- 不是特别重要
- 第一个比后两个重要,第一个除了可以配合对于这个标志位的检查,能正确结束一个线程之外也不是很重要
- 读jdk源码时,可能会碰到线程打断相关的知识点,所以要知道
interrupt()
- t.interrupt()设中断标志位
- 打断某个线程(设置标志位===>有没有被打断过、有没有被申请打断过)
- 原来是false,调用该方法给标志位设成true
- 只是申请一下,设置一下标志位,只是给了线程一个信(号),至于线程收到这个信(号)之后要不要处理,该如何处理,这要看线程自身,看自己如何安排
-
isInterrupted()
查询某线程是否被打断过(查询标志位)
- 是否被设置过那个标志位
- 设过了来查,没设过来查
static interrupted()
- 查询当前线程(当前正在执行的线程RUNNING)是否被打断过,并重置打断标志
- 容易与第二个混淆,不需要线程对象,直接用类调用即可
- 查询是否被设置过标志位,假如设置过了(标志位为true),就重置标志位===>即将标志位设回为false
代码示例
SleepHelper帮助类(只是简答地将try……catch……扔到帮助类中)
在演示式的代码中写很多try……catch……,看起来费劲
package com.mashibing.util;
import java.util.concurrent.TimeUnit;
public class SleepHelper {
public static void sleepSeconds(int seconds) {
try {
TimeUnit.SECONDS.sleep(seconds) ;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
interrupt()与isInterrupted()
- 线程结束可以采用这种方法
- 设置一个循环,每一次循环都检查一下是否有人设置了标志位;假如有人设置了,就可以退出循环(break),结束线程===>优雅地结束线程的方案
package com.mashibing.juc.c_000_threadbasic;
import com.mashibing.util.SleepHelper;
/**
* interrupt()与isInterrupted()
* 设置标志位 + 查询标志位
*/
public class T05_Interrupt_and_isInterrupted {
public static void main(String[] args) {
Thread t = new Thread(() -> {
for (; ; ) {
// 查询出来后并不能将标志位重置
if (Thread.currentThread().isInterrupted()) {
System.out.println("Thread is interrupted!");
System.out.println(Thread.currentThread().isInterrupted());
// break;
}
}
});
t.start();
// 两秒后设中断标志位
SleepHelper.sleepSeconds(2);
t.interrupt();
}
}
interrupt与interrupted()
- interrupted()方法是一个静态成员变量(静态方法),拿的是当前线程
- interrupted()方法返回当前标志位的状态并将标志位复位(恢复)
package com.mashibing.juc.c_000_threadbasic;
import com.mashibing.util.SleepHelper;
/**
* interrupt与interrupted()
*/
public class T06_Interrupt_and_interrupted {
public static void main(String[] args) {
Thread t = new Thread(() -> {
for (; ; ) {
if (Thread.interrupted()) {
System.out.println("Thread is interrupted!");
System.out.println(Thread.interrupted());
}
}
});
t.start();
SleepHelper.sleepSeconds(2);
t.interrupt();
//思考一下,如果在这里写
System.out.println("main: " + t.interrupted());
//输出的是哪个线程的中断状态
// 输出false,虽然写的是t.interrupt,但是由于这个方法interrupted()是一个静态成员变量(静态方法),拿的是当前线程;这里的当前线程是主线程
}
}
interrupt与sleep() wait() join()
- 在sleep时、wait时、join时,一旦对其设置了标志位(interrupt打断了线程),就会抛(出)异常InterruptedException
- 抛出这个异常之后,下一步怎么处理;
- 要不要catch,还是throws
- catch之后如何处理
- 主动权还是在线程本身
- 在不间断运行的服务器里,如果有sleep方法(不建议有)、wait方法(这个有可能有)、join方法(也很少用),要想用interrupt方法让他停止的话,必须得catch住interrupt异常,然后对异常做出正确的响应===>应用程序要退出,记录日志退出;忽略这个异常,继续向下执行,循环;这个主要交给写程序的程序员处理了,没有固定的处理方式;看了这个异常怎么处理是自己的事情,并不是一打断就会终止线程
- (一旦抛出InterruptException的异常之后)catch住exception之后,默认情况下,java会自动地将(中断)标志位复位===>既然已经catch住了,说明你要处理了,赶紧给你复位复回去,以免别人再次打断,那个打断状态抓不着
package com.mashibing.juc.c_000_threadbasic;
import com.mashibing.util.SleepHelper;
/**
* interrupt与sleep() wait() join()
*/
public class T07_Interrupt_and_sleep {
public static void main(String[] args) {
Thread t = new Thread(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Thread is interrupted!");
System.out.println(Thread.currentThread().isInterrupted());
}
});
t.start();
SleepHelper.sleepSeconds(5);
t.interrupt();
}
}
package com.mashibing.juc.c_000_threadbasic;
import com.mashibing.util.SleepHelper;
/**
* interrupt与sleep() wait() join()
*/
public class T08_Interrupt_and_wait {
private static Object o = new Object();
public static void main(String[] args) {
Thread t = new Thread(() -> {
synchronized (o) {
try {
o.wait();
} catch (InterruptedException e) {
System.out.println("Thread is interrupted!");
System.out.println(Thread.currentThread().isInterrupted());
}
}
});
t.start();
SleepHelper.sleepSeconds(5);
t.interrupt();
}
}
interrupt与synchronized
- 打断一个线程能不能将一个正在竞争锁、争抢锁的线程给打断,会不会抛异常
- 不可能,不会抛异常和打断线程
- 线程在争抢锁的过程中是不可能被interrupt打断或者干扰掉的
package com.mashibing.juc.c_000_threadbasic;
import com.mashibing.util.SleepHelper;
/**
* interrupt与synchronized
*/
public class T09_Interrupt_and_sync {
private static Object o = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (o) {
// sleep方法不会释放锁,10s内这把锁归t1所有
SleepHelper.sleepSeconds(10);
}
});
t1.start();
SleepHelper.sleepSeconds(1);
Thread t2 = new Thread(() -> {
// t2去抢那把锁,只有等t1线程执行完了才能抢到,那么这是能将线程打断吗?
synchronized (o) {
}
System.out.println("t2 end!");
});
t2.start();
SleepHelper.sleepSeconds(1);
// 只是设标志位,不是将线程打折腿
// 设标志位之后该抢锁还是得抢锁,不会理会标志位设不设
t2.interrupt();
}
}
interrupt与lock
- 设标志位能不能干扰(最好不要说打断)juc中的ReentrantLock这种新型的锁
- 经验证,也不会干扰到
- 如果说有一个线程持有了一把锁总是不释放,另外一个线程去申请这把锁的时候,中间过程是干扰(interrupt)不到的
- 像干扰到怎么做===>lock与synchronized的重要区别,lock可以使用lockInterruptibly()方法
package com.mashibing.juc.c_000_threadbasic;
import com.mashibing.util.SleepHelper;
import java.util.concurrent.locks.ReentrantLock;
/**
* interrupt与lock
*/
public class T10_Interrupt_and_lock {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
lock.lock();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
System.out.println("t1 end!");
});
t1.start();
SleepHelper.sleepSeconds(1);
Thread t2 = new Thread(() -> {
lock.lock();
try {
} finally {
lock.unlock();
}
System.out.println("t2 end!");
});
t2.start();
SleepHelper.sleepSeconds(1);
t2.interrupt();
}
}
interrupt与lockInterruptibly()
- 解决interrupt不能干扰到lock锁住的线程的问题
- 线程在抢锁的过程中还盯着有没有人设自己的标志位,如果有人设自己的标志位,则抛异常
- catch住异常之后怎么处理,是继续抢这把锁,还是要放弃了,交给线程,交给程序员自己处理
- 如果想打断锁争抢的过程,如果想允许interrupt方法干扰抢锁过程,用ReentrantLock中的lockInterruptibly方法
package com.mashibing.juc.c_000_threadbasic;
import com.mashibing.util.SleepHelper;
import java.util.concurrent.locks.ReentrantLock;
/**
* interrupt与lockInterruptibly()
*/
public class T11_Interrupt_and_lockInterruptibly {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
lock.lock();
try {
SleepHelper.sleepSeconds(10);
} finally {
lock.unlock();
}
System.out.println("t1 end!");
});
t1.start();
SleepHelper.sleepSeconds(1);
Thread t2 = new Thread(() -> {
System.out.println("t2 start!");
try {
// 可以被打断的过程
lock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
System.out.println("t2 end!");
});
t2.start();
SleepHelper.sleepSeconds(1);
t2.interrupt();
}
}
总结
- interrupt有一个很好的作用===>优雅地中断一个线程(中断线程有好多种方法)