首页 > 编程语言 >JUC并发编程

JUC并发编程

时间:2024-12-14 13:04:16浏览次数:5  
标签:JUC 编程 park 阻塞 LockSupport 并发 线程 唤醒 wait

LockSupport

文章目录

1. LockSupport是什么

  1. LockSupport是用于创建锁和其他同步类基本线程阻塞原语
  2. LockSupport没有构造函数,说明不可以new对象,只可以使用静态方法
  3. 核心方法就是 park() 和 unpark()
  4. park()除非许可证可用,否则禁用当前线程
  5. unpark(Thread):如果给定线程不可用,则为其提供许可
  6. park()和unpark()分别是阻塞线程解除被阻塞的线程
  7. LockSupport就是对线程等待唤醒机制(wait()/notify())的优化

2. 线程等待唤醒机制

  1. 使用Object中的wait()让线程等待,使用notify()唤醒等待的线程
    1. 通过调用对象的wait()来阻塞,然后再调用该对象的notify()来唤醒被阻塞的线程
    2. wait()方法会释放当前对象的锁,会释放当前对象的锁,而sleep()方法不会释放调用对象的锁
    3. wait 方法释放了锁,但是t1线程是阻塞状态不可以争夺cpu时间片,当t2线程notify之后唤醒t1线程并进入就绪态后才可以争夺cpu时间片进行运行
    4. 如果要使用wait()和notify(),必须要包在Synchronized代码块内
    5. 必须在获得某个对象的锁之后,才可以调用该对象的wait()和notify()方法来阻塞唤醒线程,故wait和notify必须在Synchronized代码块或者方法内,且使用锁对象调用
    6. 通过对象的wait()和notify()可以实现线程阻塞和唤醒,但必须是同一个对象才可以唤醒被阻塞的线程,且必须获得对象的锁之后才可以调用对象的wait()和notify()方法来阻塞唤醒线程
    7. 且如果使用对象的wait()和notify()来阻塞唤醒线程,则此时如果顺序出错,则会导致线程一直阻塞,必须先获得对象的锁之后,才可以调用对象的wait和notify来阻塞唤醒线程,且wait会释放当前对象的锁
    8. 必须保证wait之后再notify,否则会出现线程一直阻塞现象,不是死锁,因为只有一个线程一直阻塞
    9. 死锁是两个或以上线程因为竞争资源而造成的相互等待现象
  2. 使用JUC包中Lock锁对象的Condition的await()让线程等待,使用signal()唤醒线程
    1. 通过对象的wait()和notify()可以实现线程的阻塞和唤醒,但必须保证先获得对象的锁,即必须在Synchronized代码块中;且必须保证先wait之后再notify,否则会导致一直阻塞
    2. 通过Lock锁对象.newCondition()创建Condition对象,然后通过c1.await()阻塞线程,再通过c1.signal()唤醒被阻塞的线程
    3. 通过JUC中Lock锁对象自带的Condition的await()和signal()也可以实现线程的噪声和唤醒
    4. 使用Condition对象阻塞唤醒线程时,依旧要确保先加锁,必须先获得创建Condition对象的Lock锁之后才可以使用该Condition对象的await和signal;Condition的await和signal也必须在lock和unLock锁块之中使用
    5. 且必须要保证先await()阻塞线程之后再signal()唤醒线程,否则会导致线程一直阻塞,此时不是死锁,因为只有一个线程阻塞,而不是两个或以上相互竞争资源
  3. 使用LockSupport的park()阻塞线程,使用unpark()唤醒线程
    1. 使用Object对象的wait()和notify()或者使用Condition对象的await()和signal()可以实现线程阻塞唤醒机制,但都必须满足必须先加锁,然后才可以调用方法;且必须先阻塞后再唤醒,保证顺序不变,否则会导致线程一直阻塞
    2. LockSupport的park()和unpark()也可以实现线程的噪声和唤醒,且park()是当没有许可时阻塞线程,而unpark(Thread)是如果线程没有许可则给其许可,且通过LockSupport的静态方法来调用,故此时不需要先加锁,而且可以先unpark()后再park()
    3. LockSupport是创建锁和其他同步类的基本线程阻塞原语,通过park()和unpark()来阻塞和唤醒线程,且使用Permit许可来做到阻塞和唤醒线程,每一个线程都有最多一个许可,如果存在许可证,则park()不会阻塞,且会消耗许可证;最多只可以拥有一个许可证,且每次park都会消耗一个许可证,且许可证不可以累积,通过unpark(Thread)来获得许可证
    4. LockSupport的park()调用的是UNSAFE类的park(boolean,time阻塞时间),其底层调用的是native的park(),且当线程没有许可时就会阻塞time时间,此时就需要别的线程通过unpark(thread)来给线程许可来唤醒
    5. 当线程调用LockSupport.park()后,如果该线程没有许可,则会阻塞,直到其他线程通过unpark(thread)给指定线程一个许可后才可以使其唤醒;每一个线程最多只可以有一个许可,且每次park()都会消耗一个许可
    6. Java底层是使用C++实现
    7. 如果使用Object对象的wait()/notify(),或者使用JUC中的Condition对象的await()和signal()实现线程阻塞和唤醒时,此时必须要先获得锁对象,即必须在锁块中才可以调用函数,且必须保证先阻塞再唤醒;为了克服这些限制,可以使用LockSupport的park()和unpark()来实现线程阻塞和唤醒,此时不需要在锁块中调用,直接使用LockSupport的静态方法,且不需要保证调用顺序,因为其是使用permit许可来实现的
    8. LockSupport不需要先加锁直接就可以实现线程的阻塞和唤醒,不需要先加锁,直接进行线程阻塞和唤醒,通过LockSupport.park()来加锁,通过LockSupport.unpark(Thread)来对线程唤醒,park()会消耗permit许可,而unpark()会增加许可,最多只可以有一个许可
    9. LockSuport不需要先加锁,而且可以先唤醒再阻塞,顺序相反不会影响
    10. 使用LockSupport时不需要关注执行顺序,顺序相反仍可以实现,此时可以确保某个代码执行完成后再让另一个代码执行

3. LockSupport

  1. LockSupport通过许可来实现阻塞和唤醒,且每一个线程最多只有一个许可,此时unpark()后不会再增加许可
  2. LockSupport是创建锁和其他类的线程阻塞原语,是线程阻塞的工具类,与Object的wait/notify以及Condition的await/signal相比,不需要先加锁,而且唤醒和阻塞顺序不影响最终结果通过静态方法park()和unpark(thread)来实现阻塞和唤醒;通过permit许可来实现,且每一个线程最多只可以有一个许可,且每次park()均会消耗一个许可,如果没有许可时就会阻塞,此时必须让别的线程通过unpark来给其许可才会唤醒
  3. Object和Condition的线程阻塞唤醒机制,必须先获得对应对象的锁,然后调用同一个对象的阻塞和唤醒方法才可以实现线程阻塞和唤醒
  4. 每一个线程最多只可以有一个许可,故多次unpark()的结果是一样的

标签:JUC,编程,park,阻塞,LockSupport,并发,线程,唤醒,wait
From: https://blog.csdn.net/LiuYQi/article/details/144461574

相关文章

  • 阅记-横向优化-底层架构-《HPC-一文彻底搞懂并发编程与内存屏障》
    目录MomoryOrdering9.2.3.2NeitherLoadsNorStoresAreReordered9.2.3.3StoresAreNotReorderedWithEarlierLoads9.2.3.4LoadsMayBeReorderedwithEarlierStores(intelx64架构下唯一会有memoryreorder的情况)内存屏障的实现参考:HPC(高性能计算第一篇):一文彻......
  • 一对一视频源码,如何实现并发可重试的线程池?
    一对一视频源码,优雅的实现循环重试在一对一视频源码开发工作中,重处理是一个非常常见的场景,比如:发送消息失败。调用远程服务失败。争抢锁失败。这些错误可能是因为网络波动造成的,等待过后重处理就能成功。通常来说,会用try/catch,while循环之类的语法来进行重处理,但是这样的做法缺......
  • 使用 Crystal 编程语言实现验证码识别自动化流程
    说明Crystal是一种静态类型的、编译型编程语言,具有类似Ruby的语法,但提供了更高的性能和效率。它是一种面向开发高性能应用程序的语言,且在web编程中也有应用。我们将使用Crystal来实现一个模拟的验证码处理流程。代码实现假设我们在进行一个自动化测试任务,需要处理图......
  • 我们来学mysql -- 事务并发之不可重复读(原理篇)
    事务并发之不可重复读题记不可重复读系列文章题记在《事务之概念》提到事务对应现实世界的状态转换,这个过程要满足4个特性这世界,真理只在大炮射程之类,通往和平的道路,非“常人”可以驾驭一个人生活按部就班,人多起来,难免鸡飞狗跳同理现实世界的状态转换映射到数据库,满......
  • 解释下JavaScript并发模型
    JavaScript的并发模型在前端开发中扮演着至关重要的角色,它使得JavaScript能够在单线程环境中高效地处理异步任务,从而提供流畅的用户体验。以下是对JavaScript并发模型的详细解释:一、并发与并行的区别并发:指的是多个任务同时进行调度,但不一定在同一时刻执行。在JavaScript中,这主......
  • 在CodeBolcks+Windows API下的C++编程教程——给你的项目中添加头文件和菜单
    0.前言我想通过编写一个完整的游戏程序方式引导读者体验程序设计的全过程。我将采用多种方式编写具有相同效果的应用程序,并通过不同方式形成的代码和实现方法的对比来理解程序开发更深层的知识。了解我编写教程的思路,请参阅体现我最初想法的那篇文章中的“1.编程计划”:学习编程......
  • 转载:【AI系统】算子开发编程语言 Ascend C
    本文将深入探讨昇腾算子开发编程语言AscendC,这是一种专为昇腾AI处理器算子开发设计的编程语言,它原生支持C和C++标准规范,最大化匹配用户的开发习惯。AscendC通过多层接口抽象、自动并行计算、孪生调试等关键技术,极大提高算子开发效率,助力AI开发者低成本完成算子开发和模......
  • 转载:【AI系统】Ascend C 编程范式
    AI的发展日新月异,AI系统相关软件的更新迭代也是应接不暇,作为一篇讲授理论的文章,我们将尽可能地讨论编程范式背后的原理和思考,而少体现代码实现,以期让读者理解AscendC为何这样设计,进而随时轻松理解最新的AscendC算子的编写思路。本文将针对AscendC的编程范式进行详细讲......
  • 前端 AI 应用开发实战:构建高性能的 AI 辅助编程系统
    "能不能让AI直接在我的代码编辑器里帮我写代码?"两个月前,我们团队接到了这样一个挑战。作为一名前端工程师,我深知在浏览器中构建一个复杂的AI编程助手并非易事。今天,我想分享我们是如何一步步实现这个系统的。......
  • 转载:【AI系统】Ascend C 编程范式
    AI的发展日新月异,AI系统相关软件的更新迭代也是应接不暇,作为一篇讲授理论的文章,我们将尽可能地讨论编程范式背后的原理和思考,而少体现代码实现,以期让读者理解AscendC为何这样设计,进而随时轻松理解最新的AscendC算子的编写思路。本文将针对AscendC的编程范式进行详细讲......