当前位置:首页 > 科技  > 软件

没看过ReentrantLock源码,别说精通Java并发编程

来源: 责编: 时间:2024-03-18 09:36:21 264观看
导读引言高手程序员与新手程序员一个简单的判断标准,就是有没有使用过CountDownLatch,在互联网公司工作超过3年的程序员基本上应该都用过。CountDownLatch中文名称叫做闭锁,也叫计数锁,不过不是用来加锁的,而是通过计数实现条

引言

高手程序员与新手程序员一个简单的判断标准,就是有没有使用过CountDownLatch,在互联网公司工作超过3年的程序员基本上应该都用过。CountDownLatch中文名称叫做闭锁,也叫计数锁,不过不是用来加锁的,而是通过计数实现条件等待的功能。CountDownLatch的使用场景有两个:pWP28资讯网——每日最新资讯28at.com

  1. 当前线程等待其他线程都执行完成之后,再执行。
  2. 所有线程满足条件后,再一起执行。

使用示例

CountDownLatch常用的方法就两个,countDown()方法用来将计数器减一,await()方法会阻塞当前线程,直到计数器值等于0。pWP28资讯网——每日最新资讯28at.com

场景1:

先看一下第一种场景,也是最常用的场景:pWP28资讯网——每日最新资讯28at.com

  • 当前线程等待其他线程都执行完成之后,再执行。

在工作中什么时候会遇到这种场景呢?比如当前线程需要查询3个数据库,并且把查询结果汇总返回给前端。查询3个数据库的逻辑,可以分别使用3个线程加快查询速度。但是怎么判断3个线程都执行结束了呢?这时候就可以使用CountDownLatch了。pWP28资讯网——每日最新资讯28at.com

import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * @author 一灯架构 * @apiNote CountDownLatch测试类(场景1) **/public class CountDownLatchTest1 {    public static void main(String[] args) throws InterruptedException {        // 1. 创建一个线程池,用来执行3个查询任务        ExecutorService executorService = Executors.newFixedThreadPool(3);        // 2. 创建一个计数锁,数量是3        CountDownLatch countDownLatch = new CountDownLatch(3);        // 3. 启动3个查询任务        for (int i = 0; i < 3; i++) {            executorService.submit(() -> {                try {                    // 4. 睡眠1秒,模拟任务执行过程                    Thread.sleep(1000);                    System.out.println(Thread.currentThread().getName() + " 执行完成");                    // 5. 任务执行完成,计数器减一                    countDownLatch.countDown();                } catch (InterruptedException e) {                }            });        }        // 6. 等待所有任务执行完成        countDownLatch.await();        System.out.println("所有任务执行完成。");        // 7. 关闭线程池        executorService.shutdown();    }}

输出结果:pWP28资讯网——每日最新资讯28at.com

pool-1-thread-2 执行完成 pool-1-thread-1 执行完成 pool-1-thread-3 执行完成 所有任务执行完成。pWP28资讯网——每日最新资讯28at.com

需要注意的是,这里创建CountDownLatch计数器的时候,指定的数量是3,因为有3个任务。在3个任务没有执行完成之前,await()方法会一直阻塞,直到3个任务都执行完成。pWP28资讯网——每日最新资讯28at.com

场景2

再看一下第二种场景,有些情况用的也比较多:pWP28资讯网——每日最新资讯28at.com

  • 所有线程满足条件后,再一起执行。

什么情况下会遇到这种场景呢?比如系统中多个任务线程存在先后依赖关系,必须等待其他线程启动完成后,才能一起执行。pWP28资讯网——每日最新资讯28at.com

/** * @author 一灯架构 * @apiNote CountDownLatch测试类(场景2) **/public class CountDownLatchTest {    public static void main(String[] args) throws InterruptedException {        // 1. 创建一个线程池,用来执行3个任务        ExecutorService executorService = Executors.newFixedThreadPool(3);        // 2. 创建一个计数锁,数量是1        CountDownLatch countDownLatch = new CountDownLatch(1);        // 3. 启动3个任务        for (int i = 0; i < 3; i++) {            executorService.submit(() -> {                try {                    System.out.println(Thread.currentThread().getName() + " 启动完成");                    // 4. 等待其他任务启动完成                    countDownLatch.await();                    // 5. 睡眠1秒,模拟任务执行过程                    Thread.sleep(1000);                    System.out.println(Thread.currentThread().getName() + " 执行完成");                } catch (InterruptedException e) {                }            });        }        // 6. 所有任务启动完成,计数器减一        countDownLatch.countDown();        System.out.println("所有任务启动完成,开始执行。");        // 7. 关闭线程池        executorService.shutdown();    }}

输出结果:pWP28资讯网——每日最新资讯28at.com

pool-1-thread-1 启动完成 pool-1-thread-2 启动完成 pool-1-thread-3 启动完成 所有任务启动完成,开始执行。 pool-1-thread-1 执行完成 pool-1-thread-3 执行完成 pool-1-thread-2 执行完成pWP28资讯网——每日最新资讯28at.com

需要注意的是,与场景1不同,这里创建CountDownLatch计数器的时候,指定的数量是1,因为3个任务需要满足同一个条件,就是都启动完成,也就是只需要调用一次countDown()方法。 看完了CountDownLatch的使用方式,再看一下CountDownLatch的源码实现。pWP28资讯网——每日最新资讯28at.com

类属性

public class CountDownLatch {    // 只有一个Sync同步变量    private final Sync sync;    // Sync继承自AQS,主要逻辑都在这里面    private static final class Sync extends AbstractQueuedSynchronizer {        // 只有这一个构造方法,需要指定计数器数值        Sync(int count) {            setState(count);        }        int getCount() {            return getState();        }        protected int tryAcquireShared(int acquires) {            return (getState() == 0) ? 1 : -1;        }        protected boolean tryReleaseShared(int releases) {            for (;;) {                int c = getState();                if (c == 0)                    return false;                int nextc = c-1;                if (compareAndSetState(c, nextc))                    return nextc == 0;            }        }    }}

跟ReentrantLock一样,CountDownLatch也没有直接继承AQS,也是采用组合的方式,使用Sync同步变量实现计数的功能,而Sync同步变量才是真正继承AQS的。pWP28资讯网——每日最新资讯28at.com

countDown方法源码

public void countDown() {    // 底层调用父类AQS中的releaseShared()方法    sync.releaseShared(1);}

countDown()方法里面调用的是父类AQS中的releaseShared()方法,而releaseShared()方法又在调用子类Sync中tryReleaseShared()方法。pWP28资讯网——每日最新资讯28at.com

/** * 父类AQS */public abstract class AbstractQueuedSynchronizer        extends AbstractOwnableSynchronizer        implements java.io.Serializable {                public final boolean releaseShared(int arg) {        // tryReleaseShared()由子类实现        if (tryReleaseShared(arg)) {            doReleaseShared();            return true;        }        return false;    }    // 定义抽象方法,由子类实现    protected boolean tryReleaseShared(int arg) {        throw new UnsupportedOperationException();    }}
/** * 子类Sync */private static final class Sync extends AbstractQueuedSynchronizer {        // 实现父类AQS中的tryReleaseShared()方法    @Override    protected boolean tryReleaseShared(int releases) {        for (;;) {            int c = getState();            if (c == 0) {                return false;            }            int nextc = c-1;            if (compareAndSetState(c, nextc)) {                return nextc == 0;            }        }    }}

而Sync同步类中tryReleaseShared()方法逻辑也很简单,就是把同步状态state值减一。pWP28资讯网——每日最新资讯28at.com

await源码

await()方法底层也是调用父类中acquireSharedInterruptibly()方法,而父类AQS又需要调用子类Sync中的具体实现。pWP28资讯网——每日最新资讯28at.com

public void await() throws InterruptedException {    // 底层调用父类AQS中的releaseShared()方法    sync.acquireSharedInterruptibly(1);}
/** * 父类AQS */public abstract class AbstractQueuedSynchronizer        extends AbstractOwnableSynchronizer        implements java.io.Serializable {    public final void acquireSharedInterruptibly(int arg) throws InterruptedException {        if (Thread.interrupted()) {            throw new InterruptedException();        }        // tryAcquireShared()由子类实现        if (tryAcquireShared(arg) < 0) {            doAcquireSharedInterruptibly(arg);        }    }    // 定义抽象方法,由子类实现    protected int tryAcquireShared(int arg) {        throw new UnsupportedOperationException();    }}

子类Sync只需要实现tryAcquireShared()方法即可,而tryAcquireShared()方法的作用就是判断锁是否已经完全释放,即同步状态state=0。pWP28资讯网——每日最新资讯28at.com

/** * 子类Sync */private static final class Sync extends AbstractQueuedSynchronizer {    // 实现父类AQS中的tryAcquireShared()方法    @Override    protected int tryAcquireShared(int acquires) {        return (getState() == 0) ? 1 : -1;    }}

总结

看完了CountDownLatch的所有源码,是不是觉得CountDownLatch逻辑很简单。pWP28资讯网——每日最新资讯28at.com

因为加锁流程的编排工作已经在父类AQS中实现,子类只需要实现具体的加锁逻辑即可,也就是实现tryReleaseShared()方法和tryAcquireShared()方法。而加锁逻辑也很简单,也就是修改同步状态state的值即可。想要详细了解父类AQS的流程,可以翻看前几篇文章。pWP28资讯网——每日最新资讯28at.com

下篇文章再一块学习一下共享锁Semaphore的源码实现。pWP28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-76485-0.html没看过ReentrantLock源码,别说精通Java并发编程

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 工作中最常见的六种OOM问题

下一篇: 一个很有意思的Spring注入问题,你遇到过吗?

标签:
  • 热门焦点
  • Redmi Buds 4开箱简评:才199还有降噪 可以无脑入

    在上个月举办的Redmi Note11T Pro系列新机发布会上,除了两款手机新品之外,Redmi还带来了两款TWS真无线蓝牙耳机产品,Redmi Buds 4和Redmi Buds 4 Pro,此前我们在Redmi Note11T
  • vivo TWS Air开箱体验:真轻 臻好听

    在vivo S15系列新机的发布会上,vivo的最新款真无线蓝牙耳机vivo TWS Air也一同发布,本次就这款耳机新品给大家带来一个简单的分享。外包装盒上,vivo TWS Air保持了vivo自家产
  • 一年经验在二线城市面试后端的经验分享

    忠告这篇文章只适合2年内工作经验、甚至没有工作经验的朋友阅读。如果你是2年以上工作经验,请果断划走,对你没啥帮助~主人公这篇文章内容来自 「升职加薪」星球星友 的投稿,坐
  • 一文掌握 Golang 模糊测试(Fuzz Testing)

    模糊测试(Fuzz Testing)模糊测试(Fuzz Testing)是通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法。可以用来发现应用程序、操作系统和网络协议等中的漏洞或
  • 小红书1周涨粉49W+,我总结了小白可以用的N条涨粉笔记

    作者:黄河懂运营一条性教育视频,被54万人&ldquo;珍藏&rdquo;是什么体验?最近,情感博主@公主是用鲜花做的,火了!仅仅凭借一条视频,光小红书就有超过128万人,为她疯狂点赞!更疯狂的是,这
  • ESG的面子与里子

    来源 | 光子星球撰文 | 吴坤谚编辑 | 吴先之三伏大幕拉起,各地高温预警不绝,但处于厄尔尼诺大&ldquo;烤&rdquo;之下的除了众生,还有各大企业发布的ESG报告。ESG是&ldquo;环境保
  • 认真聊聊东方甄选:如何告别低垂的果实

    来源:山核桃作者:财经无忌爆火一年后,俞敏洪和他的东方甄选依旧是颇受外界关心的&ldquo;网红&rdquo;。7月5日至9日,为期5天的东方甄选&ldquo;甘肃行&rdquo;首次在自有App内直播,
  • 华为发布HarmonyOS 4:更好玩、更流畅、更安全

    在8月4日的华为开发者大会2023(HDC.Together)大会上,HarmonyOS 4正式发布。自2019年发布以来,HarmonyOS一直以用户为中心,经历四年多的发展HarmonyOS已
  • 三星Galaxy Z Fold/Flip 5国行售价曝光 :最低7499元/12999元起

    据官方此前宣布,三星将于7月26日也就是明天在韩国首尔举办Unpacked活动,届时将带来带来包括Galaxy Buds 3、Galaxy Watch 6、Galaxy Tab S9、Galaxy
Top