广告位联系
返回顶部
分享到

线程阻塞唤醒工具LockSupport使用介绍

java 来源:互联网 作者:佚名 发布时间:2023-08-22 22:09:22 人浏览
摘要

LockSupport 简介 LockSupport是 Java 并发编程中一个非常重要的组件,我们熟知的并发组件Lock、线程池、CountDownLatch等都是基于AQS实现的,而AQS内部控制线程阻塞和唤醒又是通过LockSupport来实

LockSupport 简介

LockSupport 是 Java 并发编程中一个非常重要的组件,我们熟知的并发组件 Lock、线程池、CountDownLatch 等都是基于 AQS 实现的,而 AQS 内部控制线程阻塞和唤醒又是通过 LockSupport 来实现的。

从该类的注释上也可以发现,它是一个控制线程阻塞和唤醒的工具,与以往的不同是它解决了曾经 wait()、notify()、await()、signal() 的局限。

回顾 synchronized 和 Lock

我们知道 Java 中实现并发安全通常会通过这两种加锁的方式,对于 synchronized 加锁的方式,如果我们想要控制线程的阻塞和唤醒是通过锁对象的 wait() 和 notify() 方法,以下面循环交替打印 AB 为例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

int status = 2;

public static void main(String[] args) throws InterruptedException {

    TestSync obj = new TestSync();

     new Thread(() -> {

        synchronized (obj){

            while (true){

                if(obj.status == 1){

                    obj.wait();

                }

                System.out.println("A");

                obj.status = 1;

                TimeUnit.SECONDS.sleep(1);

                obj.notify();

            }

        }

     }).start();

    new Thread(() -> {

       synchronized (obj){

          while (true){

              if(obj.status == 2){

                  obj.wait();

              }

              System.out.println("B");

              obj.status = 2;

              TimeUnit.SECONDS.sleep(1);

              obj.notify();

          }

       }

    }).start();

}

如果我们使用 Lock 实现类,上述代码几乎是一样的,只是先获取 Condition 对象

1

Condition condition = lock.newCondition();

把 obj.wait() 换成 condition.await(), obj.notify() 换成 condition.signal() 即可。

LockSupport 和 synchronized 和 Lock 的阻塞方式对比

技术 阻塞唤醒方式 局限
synchronized 使用锁对象的 wait()、notify() 1. 只能用在 synchronized 包裹的同步代码块中 2. 必须先 wait() 才能 notify()
Lock 使用 condition 的 await()、signal() 1. 只能用在 lock 锁住的代码块中 2. 必须先 await() 才能 signal()
LockSupport park()、unpark(Thread t) 没有限制

LockSupport 的使用

下面代码中,我们使用 LockSupport 去阻塞和唤醒线程,我们可以多次尝试,LockSupport 的 park() 和 unpark() 方法没有先后顺序的限制,也不需要捕获异常,也没有限制要在什么代码块中才能使用。

1

2

3

4

5

6

7

8

9

10

11

12

13

public static void main(String[] args) throws InterruptedException {

    Thread t1 = new Thread(() -> {

        System.out.println("A");

        LockSupport.park();

        System.out.println("被唤醒");

    });

    t1.start();

    TimeUnit.SECONDS.sleep(2);

    new Thread(() -> {

        System.out.println("B");

        LockSupport.unpark(t1);

    }).start();

}

LockSupport 注意事项

许可证提前发放

从该类的注释中我们可以看到这个类存储了使用它的线程的一个许可证,当调用 park() 方法的时候会判断当前线程的许可证是否存在,如果存在将直接放行,否则就阻塞。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

public static void main(String[] args) throws InterruptedException {

    Thread t1 = new Thread(() -> {

        try {

            TimeUnit.SECONDS.sleep(3);

        } catch (InterruptedException e) {

            throw new RuntimeException(e);

        }

        System.out.println("A");

        LockSupport.park();//不会阻塞

        System.out.println("被唤醒");

    });

    t1.start();

    TimeUnit.SECONDS.sleep(2);

    new Thread(() -> {

        System.out.println("B");

        System.out.println("先调用 unpark()");

        LockSupport.unpark(t1);

    },"t2").start();

}

看这个代码示例,这里我们在 t2 中先让线程 t1 unpark(), 然后在 t1 中调用 park(), 结果并不会阻塞 t1 线程。因为在 t2 中调用 LockSupport.unpark(t1); 的时候相当于给 t1 提前准备好了许可证。

许可证不会累计

LockSupport.unpark(t1); 无论调用多少次,t1 的通行证只有一个,当在 t1 中调用两次 park() 方法时线程依然会被阻塞。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

public static void main(String[] args) throws InterruptedException {

    Thread t1 = new Thread(() -> {

        try {

            TimeUnit.SECONDS.sleep(3);

        } catch (InterruptedException e) {

            throw new RuntimeException(e);

        }

        System.out.println("A");

        LockSupport.park();

        LockSupport.park();

        System.out.println("被唤醒");

    });

    t1.start();

    TimeUnit.SECONDS.sleep(2);

    new Thread(() -> {

        System.out.println("B");

        System.out.println("先调用 unpark()");

        LockSupport.unpark(t1);

        LockSupport.unpark(t1);

        LockSupport.unpark(t1);

        LockSupport.unpark(t1);

        LockSupport.unpark(t1);

    },"t2").start();

}

以上述代码为例,t1 将被阻塞。

LockSupport 底层实现

观察源码发现 park() 和 unpark() 最底下调用的是 native() 方法,源码在 C++ 中实现

1

2

3

4

@IntrinsicCandidate

public native void park(boolean isAbsolute, long time);

@IntrinsicCandidate

public native void unpark(Object thread);

对,这只是个标题,卷不动了,不去看 C/C++ 了。。。。

结语

LockSupport 是 Java 并发编程中非常重要的组件,这是我们下一步阅读 AQS(AbstractQueuedSynchronizer) 源码的基础。总之我们只要记住它是控制线程阻塞和唤醒的工具,并且知道它与其他阻塞唤醒方式的区别即可。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。

您可能感兴趣的文章 :

原文链接 : https://juejin.cn/post/7192019058399641658
    Tag :
相关文章
  • Spring refresh()源码解析介绍

    Spring refresh()源码解析介绍
    正文 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public void refresh() throws BeansException, IllegalStateExcept
  • 线程阻塞唤醒工具LockSupport使用介绍
    LockSupport 简介 LockSupport是 Java 并发编程中一个非常重要的组件,我们熟知的并发组件Lock、线程池、CountDownLatch等都是基于AQS实现的,而AQS内
  • RocketMQ的存储模型全介绍
    RocketMQ有Producer、Consumer、NameSrv、Broker四个部分。其中Broker用于存储消息,维护消息队列和订阅关系,是RocketMQ四个部分中最重要的一个部分
  • 规则引擎Drools的应用介绍
    现在有这么个需求,网上购物,需要根据不同的规则计算商品折扣,比如VIP客户增加5%的折扣,购买金额超过1000元的增加10%的折扣等,而且
  • Spring populateBean属性赋值和自动注入
    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { if (bw == null) { if (mbd.hasPropertyValues()) { throw new BeanCreationException( mb
  • ThreadPoolExecutor参数的用法及说明
    一、ThreadPoolExecutor核心参数说明 1、corePoolSize:核心线程数 * 核心线程会一直存活,及时没有任务需要执行 * 当线程数小于核心线程数时,即
  • springcloud gateway无法路由问题的解决
    现在企业微服务架构基本上都是用springcloud体系了,在国内基本上新项目都用springcloud alibaba,而且基本上都是所有服务聚合在一个父项目中
  • RocketMQ broker 消息投递流程处理PULL_MESSAGE请求解析
    RocketMq消息处理整个流程如下: 本系列RocketMQ4.8注释github地址,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈 消息接收:消息
  • idea搭建SSM框架遇踩的坑(附完整过程)
    首先说明这是我一个不熟悉idea和SSM框架的新手小白遇到的坑,适合用idea搭建SSM框架的小伙伴看一看,老鸟就不用看了。以下为详细步骤(傻
  • java实现文件夹上传功能的代码(SpringBoot框架)
    有时我们后台管理等服务可能会有这样一个简单需求,就是根据文件夹将整个文件夹下的所有资源都上传到我们的服务器上,本人也是搜索
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计