likes
comments
collection
share

深入理解CountDownLatch计数器

作者站长头像
站长
· 阅读数 47

深入理解CountDownLatch计数器

其他知识点

Java 多线程基础 深入理解aqs ReentrantLock用法详解 深入理解信号量Semaphore 深入理解并发三大特性 并发编程之深入理解CAS 深入理解CountDownLatch Java 线程池

使用用法

CountDownLatch用法详解

CountDownLatch实现原理

下面例子来debug一下 走走流畅


   CountDownLatch countDown = new CountDownLatch(5);

        System.out.println(" 准备多线程处理任务 ");

        IntStream.rangeClosed(1, 6).forEach(x -> {
            new Thread(() -> {
                try {
                    Thread.sleep(100000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(" 线程开始 -----  " + Thread.currentThread().getName());
                countDown.countDown();
            }, x + "").start();

        });

        try {
            countDown.await();
//            可以设置等待时间
//            countDown.await(6, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(" 准备多线程处理任务 结束 ");
        System.out.println(" ---------------------- ");
        System.out.println(" 结束 mian ---------- ");

使用 的时候,会在 countDown.await(); 进行阻塞,countDown.countDown();会去计数。

那内部原理是如何的呢?我们来debug一下

t0线程

默认是计数减1 深入理解CountDownLatch计数器

tryReleaseShared 方法

深入理解CountDownLatch计数器

可以看到初始化state是 5 这里每个线程都是 -1 然后cas设置值 深入理解CountDownLatch计数器

剩下的t2 t3 t4 t5线程都是如此

最后我们来看 await 方法

深入理解CountDownLatch计数器

首先由于我们是main线程里await 其他线程是异步的 一定会在awite这里阻塞住,会进入到这里,判断state变量是否为 0

深入理解CountDownLatch计数器

可以看到state为 0 就返回 1 否则就返回 -1 深入理解CountDownLatch计数器

然后 构建main线程节点 然后重试获取state 变量

深入理解CountDownLatch计数器

这里 shouldParkAfterFailedAcquire 方法设置node头节点 变量为 -1 再次循环返回true ,最后进入 parkAndCheckInterrupt() 方法 park main线程

知道所有线程执行完,进入 doReleaseShared() 方法 唤醒main线程

深入理解CountDownLatch计数器

可以看到头结点 下个node节点线程是main线程

深入理解CountDownLatch计数器

然后使用下面unpark 唤醒main线程

深入理解CountDownLatch计数器

最后

CountDownLatch实现原理 底层基于 AbstractQueuedSynchronizer 实现,CountDownLatch 构造函数中指定的 count直接赋给AQS的state;

深入理解CountDownLatch计数器

每次countDown()则都是release(1)减1,最后减到0时unpark阻 塞线程;

深入理解CountDownLatch计数器

这一步是由最后一个执行countdown方法的线程执行的。

而调用await()方法时,当前线程就会判断state属性是否为0,如果为0,则继续往下执 行,如果不为0,则使当前线程进入等待状态,直到某个线程将state属性置为0,其就会唤醒在 await()方法中等待的线程。

深入理解CountDownLatch计数器

CountDownLatch与Thread.join的区别

在没有 之前,我们可以使用 join 进行阻塞,等待其他线程完成操作。

CountDownLatch与Thread.join的区别

  • CountDownLatch的作用就是允许一个或多个线程等待其他线程完成操作,看起来 有点类似join() 方法,但其提供了比 join() 更加灵活的API。
  • CountDownLatch可以手动控制在n个线程里调用n次countDown()方法使计数器 进行减一操作,也可以在一个线程里调用n次执行减一操作。 join() 的实现原理是不停检查join线程是否存活,如果 join 线程存活则让当前线 程永远等待。

两者之间相对来说还是CountDownLatch使用起来较为灵活。

join方法 深入理解CountDownLatch计数器

转载自:https://juejin.cn/post/7231804086382034999
评论
请登录