interrupt
线程在调用可中断方法进入阻塞时,可由其他线程调用interrupt()进行打断,打断的线程并不是生命周期结束,而是打断当前的阻塞状态。线程调用可中断方法进入阻塞状态下被打断会抛出InterruptedException异常,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();
}
可中断方法
Object 的wait()
Thread 的 sleep()
Thread 的 join()
InterruptibleChannel 的io操作
Selector 的 wakeup()等
线程打断阻塞测试
Thread t = new Thread(()->{
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
System.out.println("休眠被打断");
}
});
t.start();
TimeUnit.MILLISECONDS.sleep(2);
t.interrupt();
输出 休眠被打断
isInterrupted
判断当前线程是否中断,不影响标识状态。
测试1:
Thread t = new Thread(()->{
while(true) {
}
});
//设置卫守护线程 不然线程不会终止
t.setDaemon(true);
t.start();
System.out.println("Thread is Interrupted "+t.isInterrupted());
TimeUnit.MILLISECONDS.sleep(2);
t.interrupt();
System.out.println("Thread is Interrupted "+t.isInterrupted());
输出
Thread is Interrupted false
Thread is Interrupted true
测试2:
Thread t = new Thread() {
@Override
public void run() {
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
System.out.println("I am Interrupted "+isInterrupted());
}
}
};
//设置卫守护线程 不然线程不会终止
t.setDaemon(true);
t.start();
TimeUnit.MILLISECONDS.sleep(2);
System.out.println("Thread is Interrupted "+t.isInterrupted());
t.interrupt();
TimeUnit.MILLISECONDS.sleep(2);
System.out.println("Thread is Interrupted "+t.isInterrupted());
输出
Thread is Interrupted false
I am Interrupted false
Thread is Interrupted false
从测试1和测试2结果可以看出中断方法捕获到了中断信号之后,会擦除掉interrupt的标识。
interrupted
是一个静态方法,也是用于判断当前线程是否被打断,调用该方法会直接擦除interrupt标识,如果当前线程被打断,那么第一次调用会返还true,并立马擦除interrupt标识,后面的调用到时false,除非中间线程被再次打断。
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
return isInterrupted(false);
}
isInterrupted() 方法传入true表示擦除interrupt标识,false不擦除。
测试
System.out.println("main Thread is Interrupted "+Thread.interrupted());
Thread.currentThread().interrupt();
System.out.println("main Thread is Interrupted "+Thread.currentThread().isInterrupted());
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
System.out.println("捕获中断信号");
}
输出
main Thread is Interrupted false
main Thread is Interrupted true
捕获中断信号
根据结果可以发现,如果一个线程设置了interrupt标识,再调用可中断方法会立即中断。
join
join()会使当前线程永远等待下去,直到中间被其他线程中断,或者join的线程执行结束,当前线程才会退出阻塞。可用于多线程查询结果再一起返回结果集。
测试代码
public static void main(String[] args) throws InterruptedException {
List<Thread> threads = new ArrayList<Thread>();
threads.add(creat("线程1"));
threads.add(creat("线程2"));
//启动线程
threads.forEach(Thread::start);
for(Thread tt:threads) {
tt.join();
}
for(int i=0;i<3;i++) {
System.out.println(Thread.currentThread().getName()+"##"+i);
shortSleep();
}
}
public static Thread creat(String str) {
return new Thread(()->{
for(int i=0;i<3;i++) {
System.out.println(Thread.currentThread().getName()+"##"+i);
shortSleep();
}
},str);
}
private static void shortSleep() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
输出
线程1##0
线程2##0
线程2##1
线程1##1
线程2##2
线程1##2
main##0
main##1
main##2
关闭一个线程
JDK有一个Deprecated方法stop(),该方法在关闭线程时可能不会释放掉monitor锁,所以强烈建议不要使用该方法结束线程。
- 可以捕获中断信号关闭线程
调用 interrupt()或者捕获InterruptedException异常进行处理. - 使用volatile开关控制
由于线程interrupt标识有可能被擦除,或者逻辑中不会调用中断方法,所以常用volatile修饰的开关关闭线程。
public static void main(String[] args) throws InterruptedException {
Task t = new Task();
t.start();
TimeUnit.MILLISECONDS.sleep(1);
t.close();
System.out.println("shutdown");
}
static class Task extends Thread {
private volatile boolean flag =false;
@Override
public void run() {
System.out.println("start work");
while(!flag && !isInterrupted()) {
System.out.println("线程正在运行");
}
}
public void close() {
this.flag=true;
this.interrupt();
}
}
输出
start work
线程正在运行
线程正在运行
线程正在运行
shutdown
- 抛出RuntimeException 结束线程生命周期
本文深入探讨Java中线程的中断机制,包括interrupt()方法的使用,可中断方法如sleep()、join()和wait()如何响应中断信号,以及如何通过interrupted()和isInterrupted()方法检查线程中断状态。同时,文章提供了实用的代码示例,展示了如何优雅地关闭线程,避免使用已弃用的stop()方法。
282

被折叠的 条评论
为什么被折叠?



