一文解读LockSupport

目录

LockSupport是什么?

3种让线程等待和唤醒的方法

方式1:object中的wait()==》notify()

方式2:Juc包中Condition==》await()

方式3:LockSupport类


LockSupport是什么?

LockSupport是JDK1.5中新增的一个类,用于实现线程的阻塞和唤醒。LockSupport中的park()和unpark()方法可以分别实现阻塞线程和唤醒线程的功能。和其他的线程控制方法相比,LockSupport有以下优点:可以阻塞和唤醒指定的线程,而不是像wait()和notify()方法一样只能阻塞和唤醒当前线程;不需要获取锁才能操作,而是将操作权限直接分配给调用线程;唤醒操作可以先于阻塞操作,而不像wait()方法只能等待notify()方法的唤醒。 

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

LockSupport中的park()和 unpark()的作用分别是阻塞线程和解除阻塞线程

LockSupport类中的park等待和unpark唤醒

LockSupport类使用了一种名为Pemit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),但与Semaphore不同的是,许可的累加上限是1。

permit许可证默认没有不能放行,所以一开始调park()方法当前线程就会阻塞,直到别的线程给当前线程的发放permit,park方法才会被唤醒。

调用unpark(thread)方法后,就会将thread线程的许可证permit发放,会自动唤醒park线程,即之前阻塞中的LockSuppot.pak()方法会立即返回。

3种让线程等待和唤醒的方法

方式1:object中的wait()==》notify()

使用object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程

public class Demo3 {
    public static void main(String[] args) {
        Object obj = new Object();
        new Thread(() -> {
            synchronized (obj){
                System.out.println(Thread.currentThread().getName()+"进来了...");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"醒过来了...");
            }
        }, "t1").start();

        new Thread(() -> {
            synchronized (obj){
                System.out.println(Thread.currentThread().getName()+"通知...");
                obj.notify();
            }
        }, "t2").start();
    }
}

Object 类中的 wait、notify、notifyAll 用于线程等待和唤醒的方法,都必须在 synchronized 内部执行。必须要先 wait 后 notify或者 notifyAll ,等待中的线程才会被唤醒,否则无法唤醒。

方式2:Juc包中Condition==》await()

使用Juc包中Condition的await()方法让线程等待,使用signal()方法唤醒线程

public class Demo3 {
    static Lock lock=new ReentrantLock();
    static Condition condition=lock.newCondition();
    public static void main(String[] args) {
       new Thread(() -> {
           lock.lock();
           System.out.println(Thread.currentThread().getName()+"进入");
           try {
               condition.await();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }finally {
               lock.unlock();
           }
           System.out.println(Thread.currentThread().getName()+"被唤醒");

       }, "t1").start();
       new Thread(() -> {
           lock.lock();
           condition.signal();
           System.out.println(Thread.currentThread().getName()+"通知");
           lock.unlock();
       }, "t2").start();
    }
}

Condition接口中的 await、signal、signalAll 用于线程等待和唤醒的方法,都必须在 lock 块内部执行。必须要先 await 后 signal或者 signalAll ,等待中的线程才会被唤醒,否则无法唤醒。


方式3:LockSupport类

上述两个对象object和Condition使用的限制条件
线程先要获得并持有锁,必须在锁块(synchronized或lock)中
必须要先等待后唤醒,线程才能够被唤醒

LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程

public class Demo3 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "进入");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + "被唤醒");
        }, "t1");
        t1.start();
        //3秒以后线程2去唤醒t1
        try { TimeUnit.MICROSECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"通知");
            LockSupport.unpark(t1);
        }, "t2").start();
    };
}

LockSupport优势
正常+无锁块要求
错误的先唤醒后等待,LockSupport照样支持 

public class Demo3 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "进入");
            LockSupport.park();
            LockSupport.park();//锁俩次
            System.out.println(Thread.currentThread().getName() + "被唤醒");
        }, "t1");
        t1.start();
        //3秒以后线程2去唤醒t1
        try { TimeUnit.MICROSECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"通知");
            LockSupport.unpark(t1);
            LockSupport.unpark(t1);//给俩次通行证
        }, "t2").start();
    };
}

上面的代码也会出现线程阻塞 

为什么唤醒两次后阻塞两次,但最终结果还会阻塞线程?
因为凭证的数量最多为1,连续调用两次unpark和调用一次 unpark效果一样,只会增加一个凭证;而调用两次park却需要消费两个凭证,不够,不能放行 

LockSupport 提供 park() 和 unpark() 方法实现阻塞线程和解除线程阻塞的过程

LockSupport 和每个使用它的线程都有一个许可(permit)关联。 permit 默认是 0。

  • 调用一次 unpark 就加 1 变成 1
  • 调用一次 park 会消费 permit ,也就是将 1 变成 0,同时 park 立即返回。
  • 如果再次调用 park 会变成阻塞(因为 permit 为 0 会阻塞在这里,一直到 permit 为 1),这时候调用 unpark 会把 permit 置为 1
  • 每个线程都有一个相关的 permit,permit 最多只有一个,重复调用 unpark 不会积累凭证。

简单来说:

线程阻塞需要消耗凭证(permit),这个凭证最多只有一个。

  • 当调用 park 方法时
    • 如果有凭证,则会直接消耗掉这个凭证然后正常退出
    • 如果没有凭证,就必须阻塞等待凭证可用
  • 当调用 unpark 方法时
    • 它会增加一个凭证,但凭证最多只能有一个,无法累加。

 LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻塞之后也有对应的唤醒方法。归根结底,LockSupport调用的Unsafe中的native代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/6040.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IOC、AOP、和javca面试题

一、 1、控制反转(IOC) 将创建管理对象的工作交给容器来做。在容器初始化(或在某个时间节点)通过反射机制创建好对象,在使用时直接从容器中获取。 控制反转:将对象的控制权反过来交给容器管理。 IOC实现…

既然有http 请求,为什么还要用rpc调用?

先弄明白什么是RPC。 RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之…

【面试】Java并发编程面试题

文章目录基础知识为什么要使用并发编程多线程应用场景并发编程有什么缺点并发编程三个必要因素是什么?在 Java 程序中怎么保证多线程的运行安全?并行和并发有什么区别?什么是多线程多线程的好处多线程的劣势:线程和进程区别什么是…

基于java+ssm+vue病人跟踪治疗信息管理系统的搭建及源码

源码获取方式见文末 一.需求简介 病人治疗信息管理系统采用B/S模式,实现安全、快捷、高效的病人跟踪治疗信息管理。传统手工管理模式效率低下,已无法满足病人需求。 信息化时代的到来,使得开发病人跟踪治疗信息管理系统成为必然。 本系统采…

Linux 串口RS232/485/GPS 驱动实验(移植minicom)

目录Linux 下UART 驱动框架I.MX6U UART 驱动分析硬件原理图分析RS232 驱动编写移植minicomRS232 驱动测试RS232 连接设置minicom 设置RS232 收发测试RS485 测试RS485 连接设置RS485 收发测试GPS 测试GPS 连接设置GPS 数据接收测试串口是很常用的一个外设,在Linux 下…

python入门(一)conda的使用,创建修改删除虚拟环境,以及常用命令,配置镜像

文章目录背景1.conda的下载地址:2.安装3.执行常用命令1)查看版本2)查看所有虚拟环境3)创建虚拟环境4)激活虚拟环境5)关闭虚拟环境6)删除虚拟环境7)创建python2.7的虚拟环境8)使用pyt…

命令行上的数据科学第二版 二、开始

原文:https://datascienceatthecommandline.com/2e/chapter-2-getting-started.html 贡献者:Ting-xin 在这一章中,我需要确定你能够利用命令行做数据科学,为此你需要能满足一些条件。条件主要分为三个部分:&#xff08…

SQLyog图形化界面工具【超详细讲解】

目录 一、SQLyog 介绍 二、SQLyog 社区版下载 三、SQLyog 安装 1、选择Chinese后点击OK 2、点击“下一步” 3、选择“我接受”后点击“下一步” 4、点击“下一步” 5、修改安装位置(尽量不要安装在C盘),点击“安装” 6、安装后点击“…

剥茧抽丝,细数模块化的前世今生

写在前面 本篇是前端工程化打怪升级的第 1 篇,关注专栏 | 小册传送门 | 案例代码 近几年,时常会感叹,前端,发展的太迅猛了。日新月异的新概念,异彩纷呈的新思想泉水般涌出;前端项目的复杂度、开发成本、维护…

Python 自动化指南(繁琐工作自动化)第二版:十五、使用 PDF 和 WORD 文档

原文:https://automatetheboringstuff.com/2e/chapter15/ PDF 和 Word 文档是二进制文件,这使得它们比纯文本文件复杂得多。除了文本,它们还存储大量的字体、颜色和布局信息。如果您想让您的程序读写 PDF 或 Word 文档,您需要做的…

【从零开始学习 UVM】3.5、UVM TestBench架构 —— UVM Sequencer [uvm_sequencer]

文章目录 Usage(用法)Custom Sequencer(自定义sequencer)Class Hierarchy一个 sequencer 生成数据事务作为类对象并将其发送到driver以执行。建议扩展uvm_sequencer基类,因为它包含了允许sequence与driver通信所需的所有功能。基类是由可以被sequencer处理的requset和resp…

CookieSession

目录 一. 回顾cookie 二. 会话机制Session 1. cookie:标识用户的身份信息 2. cookie 和 session 的关联区别 三. 一些常用的核心方法及原理应用 1. HttpServletRequest 类中的相关方法 2. HttpServletResponse 类中的相关方法 3. HttpSession 类中的相关方…

博客2:YOLOv5车牌识别实战教程:理论基础

摘要:本篇博客介绍了YOLOv5车牌识别的理论基础,包括目标检测的概念、YOLO系列的发展历程、YOLOv5的网络结构和损失函数等。通过深入理解YOLOv5的原理,为后续实战应用打下坚实基础。 车牌识别视频正文: 2.1 目标检测概念 目标检测…

【01 Provider HAL and Device HAL】

1. Overview Camera Provider Hal 和 Camera Device Hal3 即在Hal3 整个架构中紫色框框出来的部分中: 2. 简介 (1). Android定义了几个Interface: ICameraProvider, ICameraDevice, ICameraDeviceSession, ICameraDeviceCallback 。 Camera Hal 层去实做了这些 Interface。…

chatGPT陪你读源码

概述 chatGPT从2022年11月份崭露头角以来,一直备受关注。他的人工智能对话颠覆了以往智能对话的刻板印象,跟chatGPT聊天,感觉就像百晓生一样,什么都懂。尤其在编程方面,chatGPT可以根据实际的业务场景需求&#xff0c…

GPT-4原论文详细解读(GPT-4 Technical Report)

GPT-4原论文详细解读(GPT-4 Technical Report)返回论文和资料目录 1.导读 相比之前的GPT-3.5等大型语言模型(这里可以看我的InstructGPT解读,也方便理解本文内容),GPT-4最大的不同在于变成了多模态&#…

部署大数据集群时踩过的坑 (持续更新)

大数据集群踩过的坑 前言(必看) 如果你遇到了和我一样的问题并通过搜索引擎进入这篇文章,请善用CtrlF键搜索 该自检手册仅用于自己学习使用,记录所有自己遇到的问题。如果你没有检索到你的问题,请使用Bing或Google进行搜索 该自检手册严格…

PCB生产工艺流程一:PCB分类的三大要点

PCB生产工艺流程一:PCB分类的三大要点 PCB在材料、层数、制程上的多样化以适不同的电子产品及其特殊需求。因此其种类划分比较多,以下就归纳一些通用的区别办法,来简单介绍PCB的分类以及它的制造工艺。那么我们就从它的三个方面来分析一下吧。 1、材料…

某汽车零部件企业:定期反钓鱼演练是降低企业安全风险的优选方案

客户背景 作为一家主要从事于汽车、摩托车零部件的开发、制造和销售的中日合资企业,服务的客户大多为国内汽车生产领域领先企业,旗下进出口业务较多,该汽车零部件企业需要与海外企业一直保持着电子邮件的往来,电子邮件安全十分重…

eNSP 实现VLAN间通信实验

关于本实验本实验将通过上述方法(配置Dot1q终结子接口和VLANIF接口)实现不同VLAN间的通信,其中涵盖了与这两种方法相关的原理、配置命令和验证方法。实验目的掌握配置Dot1q终结子接口的方法,实现VLAN间通信。掌握配置VLANIF接口的…
最新文章