当前位置: 首页 > news >正文

JUC-线程中断机制和LockSupport

线程中断机制

概念

java提供了一种用于停止线程的协商机制-中断。称为中断标识协商机制。

常用API

  • public void interrupt()
    仅仅让线程的中断标志位设置为true。不进行其他操作。
  • public boolean isInterrupted()
    获取中断标志位的状态。
  • public static boolean interrupted()
    获取中断标志位的状态。并将中断标志位设置为false

如何停止中断运行的线程

volatile变量实现

private static volatile boolean isStop = false;public static void main(String[] args) {new Thread(() -> {while (true) {if (isStop) {System.out.println(Thread.currentThread().getName() + "线程isStop = true,自己退出");break;}System.out.println("-------hello interrupt--------");}}, "t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}isStop = true;}

AtomicBoolean实现

private static final AtomicBoolean atomicBoolean = new AtomicBoolean(true);public static void main(String[] args) {new Thread(() -> {while (atomicBoolean.get()) {try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("-------hello------");}}).start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}atomicBoolean.set(false);}

中断API interrupt和isInterrupted

public static void main(String[] args) {Thread t1 = new Thread(() -> {while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println("-----t1 线程被中断了,程序结束");break;}System.out.println("-----hello-------");}}, "t1");t1.start();System.out.println("t1是否被中断:" + t1.isInterrupted());try {TimeUnit.MILLISECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}t1.interrupt();System.out.println("t1是否被中断:" + t1.isInterrupted());}

注意

  • 如果线程处于正常活动状态,interrupt会将该线程中断状态位设置为true。要想该线程进行进一步处理需要自己根据中断状态为来写业务逻辑。
  • 如果线程处于阻塞状态(sleep, wait, join)在别的线程调用当前线程interrupt方法,那么线程立即退出阻塞状态,并抛出InterruptException异常,并将中断标志为清除(置为false)
Thread t1 = new Thread(() -> {while (true){if(Thread.currentThread().isInterrupted()){System.out.println(Thread.currentThread().getName()+"\t " +"中断标志位:"+Thread.currentThread().isInterrupted()+" 程序停止");break;}try {Thread.sleep(200);} catch (InterruptedException e) {Thread.currentThread().interrupt();//为什么要在异常处,再调用一次??// 阻塞状态下的线程设置中断标志位为true,会报异常。中断状态位置为false。导致死循环。因此需要再次设置为truee.printStackTrace();}System.out.println("-----hello InterruptDemo3");}}, "t1");t1.start();//暂停几秒钟线程try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }new Thread(() -> t1.interrupt(),"t2").start();

拓展:线程有哪些状态?7种状态
创建,就绪(等待CPU),运行,阻塞(等待锁对象),等待(等待事件),超时等待,结束
sleep不会释放锁。wait会释放锁。因此sleep进入等待状态。wait进入阻塞状态。

LockSupport

LockSupport是线程阻塞和唤醒的工具类。主要通过park阻塞和unpark唤醒。

线程等待唤醒机制

Synchronized锁对象的wait和notify

Object objectLock = new Object();new Thread(() -> {try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }synchronized (objectLock){System.out.println(Thread.currentThread().getName()+"\t ----come in");try {objectLock.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"\t ----被唤醒");}},"t1").start();//暂停几秒钟线程//try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }new Thread(() -> {synchronized (objectLock){objectLock.notify();System.out.println(Thread.currentThread().getName()+"\t ----发出通知");}},"t2").start();

限制:

  • 必须在Synchronized同步块中
  • wait必须在之前notify。否则通知唤醒会失效。

Lock.condition的await和signal

 Lock lock = new ReentrantLock();Condition condition = lock.newCondition();new Thread(() -> {try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }lock.lock();try{System.out.println(Thread.currentThread().getName()+"\t ----come in");condition.await();System.out.println(Thread.currentThread().getName()+"\t ----被唤醒");} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}},"t1").start();//暂停几秒钟线程//try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }new Thread(() -> {lock.lock();try{condition.signal();System.out.println(Thread.currentThread().getName()+"\t ----发出通知");}finally {lock.unlock();}},"t2").start();

LockSupport的park和unpark

Thread t1 = new Thread(() -> {try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println(Thread.currentThread().getName() + "\t ----come in"+System.currentTimeMillis());LockSupport.park();System.out.println(Thread.currentThread().getName() + "\t ----被唤醒"+System.currentTimeMillis());}, "t1");t1.start();//暂停几秒钟线程//try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }new Thread(() -> {LockSupport.unpark(t1);System.out.println(Thread.currentThread().getName()+"\t ----发出通知");},"t2").start();

优点:

  • 不需要在锁块中,本身就可以让线程同步。
  • park和unpark不需要有先后顺序。unpark相当于给了park一个凭证。unpark在park执行前也可以让park唤醒。相当于提前给了凭证。(而前面两种就不行)
  • 一个park需要一个凭证。但是不同的unpark作用于一个线程只能给一个凭证。(即是连续调用多次unpark和调用一次作用是一样的)

相关文章:

  • 数据结构:队列的链表结构(含完整代码,可复制)
  • docker安装部署Elasticsearch(ES)以及相关配置
  • 井盖异动传感器,守护脚下安全
  • C++之类的静态成员
  • 文件操作(与文件相关)相关笔记
  • 代码随想录第六十三天——被围绕的区域,太平洋大西洋水流问题,最大人工岛
  • ubuntu 20.04部署brc20 ordinals铭文
  • Python科学计算进阶:数值积分与微分求解算法应用在Python
  • JAVA获取昨日和今日日期时间
  • C++ | 四、指针、链表
  • Maxwell数据同步(增量)
  • 2024年学鸿蒙开发就业前景怎么样?
  • NLP论文阅读记录 - 2021 | WOS01 通过对比学习增强 Seq2Seq 自动编码器进行抽象文本摘要
  • img标签的奇怪问题
  • ubuntu20.04+opencv+vscode
  • [iOS]Core Data浅析一 -- 启用Core Data
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • Fabric架构演变之路
  • flask接收请求并推入栈
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • Octave 入门
  • php面试题 汇集2
  • Python中eval与exec的使用及区别
  • React系列之 Redux 架构模式
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 基于游标的分页接口实现
  • 记录:CentOS7.2配置LNMP环境记录
  • 原生 js 实现移动端 Touch 滑动反弹
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 如何在招聘中考核.NET架构师
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • #NOIP 2014# day.2 T2 寻找道路
  • #预处理和函数的对比以及条件编译
  • (Java)【深基9.例1】选举学生会
  • (备忘)Java Map 遍历
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (转)ABI是什么
  • (转)socket Aio demo
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .NET Reactor简单使用教程
  • .NET 读取 JSON格式的数据
  • .net 发送邮件
  • .NET 简介:跨平台、开源、高性能的开发平台
  • .Net 知识杂记
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .NET的微型Web框架 Nancy
  • .net和jar包windows服务部署
  • /bin、/sbin、/usr/bin、/usr/sbin
  • @require_PUTNameError: name ‘require_PUT‘ is not defined 解决方法
  • [ 2222 ]http://e.eqxiu.com/s/wJMf15Ku
  • [20150629]简单的加密连接.txt
  • [20170713] 无法访问SQL Server
  • [ai笔记4] 将AI工具场景化,应用于生活和工作
  • [BSGS算法]纯水斐波那契数列
  • [bzoj1901]: Zju2112 Dynamic Rankings