JUC之线程中断与LockSupport

什么是中断

  • 首先一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。
  • 其次在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。因此,Java提供了一种用于停止线程的机制------中断。
  • 中断只是一种协作机制,Java没有给中断增加任何语法,中断的过程完全需要程序员自己实现。若要中断一个线程,你需要手动调用该线程的interrupt方法,该方法也仅仅是将线程对象的中断标识设成true;接着你需要自己写代码不断地检测当前线程的标识位,如果为true,表示别的线程要求这条线程中断,此时究竟该做什么需要你自己写代码实现。
  • 每个线程对象中都有一个标识,用于表示线程是否被中断;该标识位为true表示中断,为false表示未中断;通过调用线程对象的interrupt方法将该线程的标识位设为true;可以在别的线程中调用,也可以在自己的线程中调用。

中断相关API

  • interrupt()设置线程的中断标识为true;
  • interrupted()返回当前的中断标识,并将其中断标识设置为false;
  • isInterrupted()判断当前线程是否被中断;

如何使用中断标识中断线程?

在需要中断的线程中不断监听中断状态,一旦发生中断,就执行相应的中断处理业务逻辑

  1. 通过一个volatile变量实现
  2. 通过Thread类自带的中断api方法实现

当前线程的中断标识为true,是不是就立刻停止?

具体来说,当对一个线程,调用 interrupt() 时:

① 如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。所以, interrupt() 并不能真正的中断线程,需要被调用的线程自己进行配合才行。

② 如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,如需要锁,则在获取锁的情况下 抛出一个InterruptedException异常。

lockInterruptibly()方法

  1. 当使用该方法获取锁时 如果在等待获取锁 则可以调用中断方法进行中断 注意在线程运行时进行中断没有任何作用(因为只是在线程中将其中断标识为true,除非自己书写代码捕获,线程不会自动中断)
  2. synchronized锁无论是获取到锁还是等待获取锁 调用中断方法都不会时线程中断. 除非在运行时自己书写代码逻辑
  3. 线程在调用wait中是时 调用中断方法会立即唤醒并在下次线程获取到锁时抛出异常 不会在调用中断方法后立即抛出异常, 并且会清除中断标记位(结束将其设置位false),当线程在sleep时,由于在调用此方法时锁并不会释放,在调用中断方法后会立即唤醒线程 由cpu再次调度后,立即抛出异常,且清除标记位;

总结

中断只是一种协同机制,修改中断标识位仅此而已,不是立刻stop打断;

LockSupport

LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。

线程等待唤醒机制

  1. 方式1:使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程;
    1. wait和notify方法必须要在同步块或者方法里面,且成对出现使用;
    2. 先wait后notify才可以;
  2. 方式2:使用JUC包中Condition的await()方法让线程等待,使用signal()方法唤醒线程;
    1. Condtion中的线程等待和唤醒方法之前,需要先获取锁;
    2. 一定要先await后signal,不要反了;
  3. 方式3:LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程;

Object和Condition使用的限制条件

  1. 线程先要获得并持有锁,必须在锁块(synchronized或lock)中;
  2. 必须要先等待后唤醒,线程才能够被唤醒;

LockSupport类中的park等待和unpark唤醒

  • 通过park()和unpark(thread)方法来实现阻塞和唤醒线程的操作
  • LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能, 每个线程都有一个许可(permit),permit只有两个值1和零,默认是零。

park()

park方法默认是0,所以调用park方法时,会将其线程阻塞;直到别的线程将当前线程的permit设置为1时,park方法会被唤醒,然后会将permit再次设置为零并返回;

unpark(Thread thread)

  • LockSupport.unpark(thread); 唤醒处于阻塞状态的指定线程;
  • 调用unpark(thread)方法后,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加,permit值还是1)会自动唤醒thread线程,即之前阻塞中的LockSupport.park()方法会立即返回。

注意事项

  1. park和unpark要成双成对的出现;
  2. LockSupport是创建锁与其他同步类的基本阻塞原语;
  3. LockSupport的许可证最多只有一个;

当调用park方法时:

  1. 如果没有许可证则阻塞等待;
  2. 如果有许可证则消耗掉许可证并退出阻塞状态;

当调用unpark方法时将许可证加一(许可证最多为一,调用多次累加无效)

相关推荐
儿时可乖了39 分钟前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol40 分钟前
java基础概念37:正则表达式2-爬虫
java
xmh-sxh-13141 小时前
jdk各个版本介绍
java
天天扭码1 小时前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺1 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序1 小时前
vue3 封装request请求
java·前端·typescript·vue
陈王卜2 小时前
django+boostrap实现发布博客权限控制
java·前端·django