系列文章目录
Java多线程【1】synchronized对象锁、内置锁使用
Java多线程【2】Java wait/notify的使用于同步模式保护性暂停
Java多线程【3】同步模式之保护性暂停案例 相亲问题
Java多线程【4】interrupt线程的打断机制、两阶段终止模式
Java多线程【5】异步模式之生产者消费者
Java多线程【6】LockSupport park/unpark原理和使用以及于wait/notify的区别
文章目录
一、为什么不用stop方法
- 线程的stop方法可以终止线程,但是是粗暴的终止,无法进行终止之后线程的执行任务。
- 无法释放终止的线程获取的锁。导致系统死锁等多线程并发问题。
二、打断阻塞状态的线程
1.线程如何主动进入阻塞状态
2.线程的sleep、join方法
sleep和join方法会使线程进入WAITING
状态
3.锁对象的wait方法
wait方法会使线程进入WAITING
状态
4.LockSupport的part方法
这方法不会抛出InterruptedException
错误
part方法会使线程进入WAITING
状态
注意:LockSupport的part方法会让线程阻塞,使用interrupt方法会直接结束阻塞,且后续的park方法将不会阻塞线程。而其他的阻塞sleep、join、wait
是通过抛出一个InterruptedException
错误让线程捕获到。
2、打断线程
注意:打断除LockSupport的part方法阻塞状态的线程,线程的打断标志会被置为false
。
1.打断sleep
Thread thread = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt();
2.打断join
Thread thread = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3);
//停止thread线程,这时主线程调用的thread.join()就会被中断
Thread.currentThread().interrupt();
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
try {
thread.join();
}catch (InterruptedException e){
e.printStackTrace();
}
2.打断wait
- 新建线程thread调用lock锁对象的wait方法阻塞
- 主线程终止thread,此时thread为阻塞状态,会直接被中断报错。
Thread thread = new Thread(() -> {
try {
synchronized (lock){
lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
try {
//thread的线程的wait()方法就会被中断
thread.interrupt();
}catch (InterruptedException e){
e.printStackTrace();
}
3.打断park
这个part是LockSupport的方法。也是让线程进入到阻塞状态。
注意:在打断标记为true的时候,再次执行park方法线程就不会被阻塞,只有将打断标记重新设置为false才生效。Thread.interrupted()
方法可以线程的打断标记重置为false。
Thread thread = new Thread(() -> {
System.out.println("park...");
LockSupport.park();
System.out.println("unPark");
});
thread.start();
try {
TimeUnit.SECONDS.sleep(1);
thread.interrupt();
}catch (InterruptedException e){
e.printStackTrace();
}
三、打断非阻塞状态的线程(两阶段终止模式)
一个线程能优雅的终止另一个线程,这种模式被称为两阶段终止模式。
- 新建thread1,thread1获取当前线程,轮询线程的中断状态,中断状态为true直接跳出循环结束线程。
- 新建thread2,睡眠10秒后中断thread1。
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("线程被打断,业务执行完毕");
break;
}
try {
System.out.println("执行业务代码中");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
//睡眠过程中会导致打断标志被重置为false
Thread.currentThread().interrupt();
}
}
}
});
Thread thread2 = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(5);
thread.interrupt();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
thread.start();
thread2.start();
}
四、总结
- stop方法的废弃原因。
- 调用线程的sleep、join方法,使用LockSupport的part方法,锁对象的wait方法会使线程进入到阻塞状态。
- 线程在LockSupport的part时被中断,会直接退出阻塞。其他的方法会以报错的形式抛出。
- 中断的处理逻辑是日常生产过程中非常重要的环节。线程的stop方法不推荐的使用一方面是因为会导致线程安全的问题,但最主要还是线程被中断后的业务逻辑无法定义。两阶段终止模式可以有效的解决以上线程中断的各种问题。