前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >话说 LockSupport

话说 LockSupport

原创
作者头像
木子的昼夜
修改于 2021-04-06 03:09:09
修改于 2021-04-06 03:09:09
4540
举报

LockSupport

LockSupport要从wait/notify/notifyAll 、condition.await/signal/signalAll 说起

在JUC包中很多地方都会使用到LockSupport 比如我们前边写的ReentrantLock中,获取锁失败之后会加入队列调用LockSupport.park() 等待前边一个获取锁的线程unpark自己

下边以小强和小月月用同一个水杯喝水为例 讲解wait/notify 、await/signal 、park/unpark

一、 wait notify

wait nofity 的详细讲解 前边文章有写过 这里只是简单实用 仅为了与LockSupport比较

代码语言:txt
AI代码解释
复制
class TestWaitNotify {
    public Object obj = new Object();
    public static void main(String[] args) {
        TestWaitNotify test = new TestWaitNotify();
        new Thread(test::xiaoqiang).start();
        new Thread(test::xiaoyueyue).start();
    }

    /**
     * 小强喝水
     */
    public void xiaoqiang(){
        synchronized (obj){
            while (true){
                try{
                    System.out.println("小强喝水");
                    //通知别人喝水
                    obj.notify();
                    // 自己wait
                    obj.wait();
                } catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 小月月喝水
     */
    public void xiaoyueyue(){
        synchronized (obj){
            while (true){
                try{
                    System.out.println("小月月喝水");
                    //通知别人喝水
                    obj.notify();
                    // 自己wait
                    obj.wait();
                } catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

}

输出结果:
小强喝水
小月月喝水
小强喝水
小月月喝水
小强喝水
小月月喝水
... 
    

小强喝完了通知别人可以喝了,然后自己等着

小月月收到通知,喝水,喝完了通知别人可以喝了,然后自己等着

如此循环往复...

wait/notify/notifyAll 还是老生常谈的问题:

代码语言:txt
AI代码解释
复制
1. 必须在synchronized代码块或者synchronized修饰的方法内  否则会报异常:java.lang.IllegalMonitorStateException
2. nofity只有在wait方法调用之后调用才能生效  先调用notify再调用wait 没用。。。
3. 线程interrupt 中断会打断wait 
二、await signal
代码语言:txt
AI代码解释
复制
class TestAwaitSignal {
    Lock lock = new ReentrantLock();
    Condition cd = lock.newCondition();
    public static void main(String[] args) {
        TestAwaitSignal test = new TestAwaitSignal();

        new Thread(test::xiaoqiang).start();
        new Thread(test::xiaoyueyue).start();
    }

    /**
     * 小强喝水
     */
    public void xiaoqiang(){
        try {
            lock.lock();
            while (true){
                try{
                    System.out.println("小强喝水");
                    //signal通知别人喝水
                    cd.signal();
                    // 自己await
                    cd.await();
                } catch (Exception e){
                    e.printStackTrace();
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 小月月喝水
     */
    public void xiaoyueyue(){
        try {
            lock.lock();
            while (true){
                try{
                    System.out.println("小月月喝水");
                    //signal通知别人喝水
                    cd.signal();
                    // 自己await
                    cd.await();
                } catch (Exception e){
                    e.printStackTrace();
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

输出结果:
小强喝水
小月月喝水
小强喝水
小月月喝水
小强喝水
小月月喝水
小强喝水
小月月喝水
小强喝水
... 

await/signal/signalAll还是老生常谈的问题:

代码语言:txt
AI代码解释
复制
1. 必须在lock获取锁代码块中执行 否则会报IllegalMonitorStateException异常
2. lock必须在finally中手动释放锁
3. signal 必须 在await之后调用  否则不起作用 
4. condition.await比wait多可中断、到达指定时(前边文章有写)间停止等功能(前边文章有写)
5. 一个lock可以new多个互不干扰的condition (前边文章有写)
三、LockSupport
3.1 使用

这是要给很好的东西

park /pɑːk/ 停车场、停放

unpark 把车从停车场离开

从一个故事走进park/unpark ,小强开着车走进一个停车场park了一下,然后他就出不去了,只能一直在停车场停着,直到小月月给他送来停车券unpark,这时候他才能出去

停车例子:

代码语言:txt
AI代码解释
复制
class TestParkUnpark {

    public static void main(String[] args) throws InterruptedException {
        TestParkUnpark test = new TestParkUnpark();
        Thread thread = new Thread(test::xiaoqiang);
        thread.start();

        Thread.sleep(5000);
        // 小月月给停车券
        new Thread(()->{
            test.xiaoyueyue(thread);
        }).start();
    }

    /**
     * 小强进入停车场
     */
    public void xiaoqiang(){
            System.out.println("停车等着出停车场");
            LockSupport.park();
            System.out.println("我出来了!!");
    }

    /**
     * 小月月给停车券
     */
    public void xiaoyueyue(Thread thread){
        System.out.println("给小强那二傻子送个停车券");
        LockSupport.unpark(thread);
    }
}
输出:
停车等着出停车场
给小强那二傻子送个停车券
我出来了!!

很明显看出来了,

代码语言:txt
AI代码解释
复制
1.LockSupport 与wait/condition.await最大的区别就是 他不要锁,不需要在锁代码块中使用
3.2 不分顺序

LockSupport还有一个特点就是unpark可以先于park执行,就是小强这二傻子去停车场之前,小月月先把停车券给他了unpark,等他想走的时候手里有停车券不需要再一次获取停车券unpark了。

代码语言:txt
AI代码解释
复制
class TestParkUnpark02 {

    public static void main(String[] args) throws InterruptedException {
        TestParkUnpark02 test = new TestParkUnpark02();
        Thread thread = new Thread(test::xiaoqiang);

        // 进入停车场
        thread.start();

        // 小月月先给停车券
        new Thread(()->{
            test.xiaoyueyue(thread);
        }).start();

    }

    /**
     * 小强进入停车场
     */
    public void xiaoqiang()   {
            try {
                // 在外边潇洒呢
                Thread.sleep(10000);
                // 进停车场了
                System.out.println("停车等着出停车场");
                LockSupport.park();
                System.out.println("我出来了!!");
            } catch (Exception e){

            }
    }

    /**
     * 小月月给停车券
     */
    public void xiaoyueyue(Thread thread){
        System.out.println("给小强那二傻子送个停车券");
        LockSupport.unpark(thread);
    }
}
输出结果:
给小强那二傻子送个停车券
停车等着出停车场
我出来了!!
3.3 可中断 可超时返回 可指定等待时间点返回
代码语言:txt
AI代码解释
复制
class TestParkUnpark03 {
    public static void main(String[] args)   {
        TestParkUnpark03 test = new TestParkUnpark03();
        // 可中断 停止park
        Thread thread = new Thread(test::xiaoqiang);
        thread.start();
        thread.interrupt();


    }
    /**
     *  可中断
     */
    public void xiaoqiang()   {
        // 进停车场了
        System.out.println("停车等着出停车场");
        LockSupport.park();
        boolean interrupted = Thread.currentThread().isInterrupted();
        if (interrupted){
            System.out.println("被中断的 强行闯卡");
        } else {
            System.out.println("拿到票 我出来了!!");
        }
    }
}
代码语言:txt
AI代码解释
复制
class TestParkUnpark04 {
    public static void main(String[] args)   {
        TestParkUnpark04 test = new TestParkUnpark04();
        // 可超时
        Thread thread = new Thread(test::xiaoqiang);
        thread.start();


    }
    /**
     *  可超时
     */
    public void xiaoqiang()   {
        // 进停车场了
        System.out.println("停车等着出停车场");
        // 5秒后自己出去
        long nanos = TimeUnit.SECONDS.toNanos(5);
        LockSupport.parkNanos(nanos);
        System.out.println("结束park 要么是给了券  要么是小强跟门卫耗了半天让他出去了");
    }
}
代码语言:txt
AI代码解释
复制
class TestParkUnpark04 {
    public static void main(String[] args)   {
        TestParkUnpark04 test = new TestParkUnpark04();
        // 可指定等待时间点 到这个点就停止park 
        Thread thread = new Thread(test::xiaoqiang);
        thread.start();


    }
    /**
     *  可指定等待时间点 到这个点就停止park 
     */
    public void xiaoqiang()   {
        // 进停车场了
        System.out.println("停车等着出停车场");
        // 10秒后自己出去
        long nanos = TimeUnit.SECONDS.toMillis(10);
        Date date= new Date(System.currentTimeMillis()+nanos);
        // 到指定时间就停止
        LockSupport.parkUntil(date.getTime());
        System.out.println("结束park 要么是给了券  要么是小强跟门卫耗了半天让他出去了  要么是到了晚上(指定时间)门卫不在 自己溜出去了");
    }
}
3.4还有一个 功能

这个功能乍一看没啥作用。

代码语言:txt
AI代码解释
复制
class TestParkUnpark04 {
    public static void main(String[] args)   {
        TestParkUnpark04 test = new TestParkUnpark04();
        new Thread(test::xiaoqiang01,"线程001").start();
        new Thread(test::xiaoqiang02,"线程002").start();

    }

    public void xiaoqiang01()   {
        // 这里传入了一个对象
        LockSupport.park();
    }
    public void xiaoqiang02()   {
        // 这里传入了一个对象
        LockSupport.park(new ParkParam());
    }
}
class ParkParam{

}

我们用jps找到当前java进程,再用jstack查看堆栈信息

代码语言:txt
AI代码解释
复制
1. 打开cmd
2. jps
	11672 TestParkUnpark04
3. jstack -l 11672
部分输出内容: 
"线程002" #12 prio=5 os_prio=0 tid=0x000000001e042800 nid=0x263c waiting on condition [0x000000001eaff000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x000000076bbb1a20> (a vip.freeedu.ParkParam)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at vip.freeedu.TestParkUnpark04.xiaoqiang02(TestParkUnpark04.java:25)
        at vip.freeedu.TestParkUnpark04$$Lambda$2/990368553.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"线程001" #11 prio=5 os_prio=0 tid=0x000000001e03f800 nid=0x25fc waiting on condition [0x000000001e9ff000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:304)
        at vip.freeedu.TestParkUnpark04.xiaoqiang01(TestParkUnpark04.java:21)
        at vip.freeedu.TestParkUnpark04$$Lambda$1/2003749087.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)
01.png
01.png

可以看到线程002 多了一行 -parking for wait for xxxx

这样我们在排查问题的时候就容易知道是哪儿出了问题 ,每个park处都new不一样的对象,这样很容易定位

3.5 LockSupport**优点出来了
代码语言:txt
AI代码解释
复制
1. 不用与锁混合使用!! 
2. 可以先unpark拿到停车券 在park的时候就可以直接用停车券通过!!
3. 可以超时停止等待 ; wait await都支持
4. 可停止到指定时间 ;await支持
5. 可中断 ;wait await都支持  await支持不响应中断

这里说一点哈 ,Object的wait也支持wait超时停止等待

3.6 注意:unpark不能累计

park和unpark的实现原理。。 我看了一下hotspot的实现 没有看懂 ,但是我看注释意思可能就是这样的,

有一个标志位_event

3.7 park

当调用park的时候就会判断_event

  1. 如果是-1 非法数据
  2. 如果是1 那就设置为0 返回(不阻塞直接过)相当于手持停车券 出停车场 顺畅无阻 (先unpark 再 park )
  3. 如果是0 那就把_event设置为-1
代码语言:txt
AI代码解释
复制
void os::PlatformEvent::park() {       // AKA "down()"
  // Transitions for _event:
  //   -1 => -1 : illegal
  //    1 =>  0 : pass - return immediately
  //    0 => -1 : block; then set _event to 0 before returning
02.png
02.png
3.8 unpark

当调用unpark**的时候就会判断_event

  1. 如果是0,设置_event为1 这就是为什么unpark可以在park之前调用,因为这里设置为1 然后park的时候就会用这个值
  2. 如果是1 返回 ,不会累积 这就是为什么unpark多次只能park使用一次
  3. 如果是-1 那就把_event设置为0 或 1 ,唤醒目标线程
代码语言:txt
AI代码解释
复制
void os::PlatformEvent::unpark() {
  // Transitions for _event:
  //    0 => 1 : just return 
  //    1 => 1 : just return
  //   -1 => either 0 or 1; must signal target thread
  //         That is, we can safely transition _event from -1 to either
  //         0 or 1.
03.png
03.png

欢迎关注公众号:

公众号二维码.jpg
公众号二维码.jpg

hygq-url-param-list=&q-signature=ee4a741f6ffeae9a3fd9ffd3268fa8803dcad5e4)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
ConstraintLayout概要
约束布局ConstraintLayout 是一个ViewGroup,可以在Api9以上的Android系统使用它,它的出现主要是为了解决布局嵌套过多的问题,以灵活的方式定位和调整小部件。
码客说
2020/07/03
9750
还在用Android正经布局来写页面吗?
ConstraintLayout布局出来已经很久了,刚出来那会儿就想尝试一下的,结果半天都没适应,前两天看到一篇ConstraintLayout实战的文章,看完之后发现这布局贼鸡儿好用啊,日常开发中的大多数布局使用它都可以完成,而且也不需要嵌套。
用户2802329
2018/09/21
1.4K0
还在用Android正经布局来写页面吗?
再学一次ConstraintLayout 一些新特性
首先,ConstraintLayout是一个新的布局,它是直接继承自ViewGroup的,所以在兼容性方面是非常好的.官方称可以兼容到API 9.可以放心食用.
Android技术干货分享
2019/03/28
1.8K0
再学一次ConstraintLayout 一些新特性
细细品读!深入浅出,官方文档看ConstraintLayout
之前品读了郭霖大神写的《Android新特性介绍,ConstraintLayout完全解析》,受其感染,写了一篇《未来布局之星——ConstraintLayout》,回过头来看,感觉这一篇文章太注重可视化操作,于是去翻阅了一下ConstraintLayout的官方文档,决定从官方文档的角度在代码层面来了解一下ConstraintLayout。
代码咖啡
2018/08/28
1.1K0
细细品读!深入浅出,官方文档看ConstraintLayout
项目需求讨论 — ConstraintLayout 详细使用教程
关于ConstraintLayout的文章网上一抓一大把,而且ConstraintLayout在16年就已经出来了,但是我一直没有试着去使用(别问我为什么不去使用,当然是因为懒啊)。毕竟前面的LinearLayout搭配RelativeLayout用习惯了,但是毕竟能减少布局的嵌套。还是要抱着多学习的方式去接触。所以写下文章作为总结。
青蛙要fly
2018/08/29
1.8K0
项目需求讨论 — ConstraintLayout 详细使用教程
布局"大杀器"—ConstraintLayout
简介:约束布局(ConstraintLayout) 是一个 ViewGroup,它的出现主要是为了解决布局嵌套过多的问题,以灵活的方式定位和调整 View。
下码看花
2019/09/02
1.6K0
布局"大杀器"—ConstraintLayout
ConstraintLayout 使用详解,减少嵌套 UI, 提升性能
对于初学者来说,可能觉得ConstraintLayout属性多,且属性长而弃用它,那你错失了这个大宝贝。
程序员徐公
2023/03/08
1.8K0
ConstraintLayout 使用详解,减少嵌套 UI, 提升性能
ConstraintLayout使用汇总
在这里我要向大家介绍ConstraintLayout,它是一种布局方法,可以帮助我们在对Android进行布局时减少对布局层次的嵌套,进而提高app的性能。
Rouse
2019/07/16
8780
ConstraintLayout(约束布局)的使用
这些属性会引用另一个控件的id或者parent(这会引用父容器,即ConstraintLayout)
用户1205080
2018/10/18
2.4K0
ConstraintLayout(约束布局)的使用
ConstraintLayout 入门指南
本文主要介绍了ConstraintLayout从诞生到如今在Android App开发中的重要性、使用场景、优缺点,以及社区的发展状况。通过实际案例和设计模式,展示了ConstraintLayout在移动开发领域的魅力,并针对实际开发中遇到的问题提供了一些解决方案。
QQ音乐技术团队
2017/09/19
2.6K0
ConstraintLayout 入门指南
笔记74 | 学习掌握ConstraintLayout的基本属性
最近一个礼拜业余时间都在搞我的淘宝店铺,有兴趣的都可搜一下:吉安车品,主营汽车脚垫/后备箱垫/座垫,还在打基础阶段,不急,慢慢搞,当业余爱好去买卖;当然吃饭手艺功夫自然也不能丢,为下个月的变数准备,今天开始复习/学习一些基础内容,今天的笔记是ConstraintLayout的几个属性。 1、Circular positioning(圆形定位) 标题后面的中文是自己翻译的,可能不是很准确。 官方文档是这么介绍的: You can constrain a widget center relative to an
项勇
2018/06/19
1.4K0
【约束布局】ConstraintLayout 之 Chains 链式约束 ( Chains 简介 | 代码 及 布局分析 | 链头设置 | 间距设置 | 风格设置 | 权重设置 )
Chains 创建后 代码 及 样式 : 下图是 官方配图 , 表示一个 最小的 链 , 只有两个 控件 , 控件两端 约束于 父控件 , 控件之间 互相约束 ;
韩曙亮
2023/03/27
3.9K0
【约束布局】ConstraintLayout 之 Chains 链式约束 ( Chains 简介 | 代码 及 布局分析 | 链头设置 | 间距设置 | 风格设置 | 权重设置 )
Constraintlayout约束布局三问
Constraintlayout——约束布局,作为Jetpack的一个组件推出。今天的面试三问就是关于布局的:
码上积木
2020/09/27
1.7K0
Infer Constraints,Autoconnect,ConstraintLayout拖拽使用教程
参考:https://developer.android.google.cn/training/constraint-layout/index.html
zhangjiqun
2024/12/16
3020
Infer Constraints,Autoconnect,ConstraintLayout拖拽使用教程
【Android从零单排系列三十四】《Android布局介绍——ConstraintLayout》
小伙伴们,在上文中我们介绍了Android帧布局FrameLayout,本文我们继续盘点介绍Android开发中另一个常见的布局,约束布局ConstraintLayout。
再见孙悟空_
2023/07/17
6420
一文看懂ConstraintLayout的用法
ConstraintLayout 相对于 RelativeLayout来说性能更好,布局上也更加灵活。在最新的Google Android开发文档中是推荐使用 ConstraintLayout的,下面来看看具体用法。
阳仔
2019/07/30
8190
一文看懂ConstraintLayout的用法
强烈建议!让你的团队强制推行ConstraintLayout!
ConstraintLayout(约束布局)在2016年的Google I/O大会上就推出来了,经历这两年的迭代,功能已经非常的成熟了。一次偶然的机会,在项目中尝试了使用约束布局,从此被它的功能所深深折服。它能很轻易的将你从使用层层的嵌套去实现复杂的布局中解放出来。使用ConstraintLayout后基本可以抛弃LinearLayout和RelativeLayout的使用。完全不需要任何嵌套就可以实现复杂的UI,使用起来特别清爽。所以相信我,使用过就会爱上它。
吴延宝
2018/10/18
9520
强烈建议!让你的团队强制推行ConstraintLayout!
1.android布局-ConstraintLayout-约束布局
ConstraintLayout 是什么? ConstraintLayout ConstraintLayout 怎么用? 基本用法 layout_constraint[当前控件位置]_[目标控件位置]="[目标控件ID]" 1.上下排列 a b b: app:layout_constraintTop_toBottomOf="a" 实例: <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.an
tea9
2022/07/16
5690
1.android布局-ConstraintLayout-约束布局
细细品读!深入浅出,官方文档看ConstraintLayout
ConstraintLayout和其他布局一样,继承自ViewGroup,但是不同点在于它调整控件的位置和大小时更加得灵活,功能更加强大。
用户2802329
2018/08/07
1K0
细细品读!深入浅出,官方文档看ConstraintLayout
强大的ConstraintLayout:使用ConstraintLayout打造响应式UI
约束布局ConstraintLayout发布(2017年)至今已经好几个年头了。经过几个版本的功能迭代,现阶段的ConstraintLayout相当强大,80%以上的复杂界面都可以使用ConstraintLayout来实现;剩下的20%里,有80%是没充分利用好ConstraintLayout的特性来实现,最后的20%,才是Android Support 包团队需要加油补上的。
Kkkiro
2019/07/19
3.1K0
推荐阅读
相关推荐
ConstraintLayout概要
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档