文档章节

多线程-AQS-CountDownLatch

重城重楼
 重城重楼
发布于 04/15 15:03
字数 1015
阅读 8
收藏 2

介绍:

CountDownLatch--发令枪
        Java1.5之后引入的Java并发工具类,谈到CountDownLatch需要先介绍一个概念:闭锁/门栓[latch]
         latch:一种同步方法,可以延迟线程的进度直到线程到达某个终点状态。闭锁的状态是一次性的,它确保在闭锁打开之前所有特定的活动都需要在闭锁打开之后才能完成。

        如若掌握了AQS的实现原理,这里的理解将会更加的水到渠成

==========================分割线==========================

应用场景
        A:如同赛跑,必须等待发令枪响后runner才能起跑一样,在CountDownLatch的计数器归零前,所有引用CountDownLatch闭锁的线程都必须阻塞。总结:准备好了才开始


        B:如同购物,只有所有商品都确定购买了才好结账,在所有任务执行完[并进行countDown()]直到归零前,当前任务必须阻塞。总结:准备好了才结束

应用A的样例[准备好了才开始]:

import java.util.concurrent.CountDownLatch;

/**
 * Created by ysma on 2018/6/7.
 */
public class Test {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch cdl = new CountDownLatch(1);
        threadX driverA = new threadX(cdl);
        threadX driverB = new threadX(cdl);
        new Thread(driverA).start();
        new Thread(driverB).start();
        System.out.println("===开始==time:"+System.currentTimeMillis()+"==count:"+cdl.getCount());
        cdl.countDown();
        Thread.sleep(10);
        System.out.println("========结束==time:"+System.currentTimeMillis()+"==count:"+cdl.getCount());

    }

    static class threadX implements Runnable {
        private CountDownLatch cdl;
        threadX(CountDownLatch cdl){
            this.cdl = cdl;
        }

        @Override
        public void run() {
            try {
                cdl.await();
                System.out.println(Thread.currentThread().getName()
                        +":running.... now:"
                + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

=============执行结果==========
===开始==time:1555310552568==count:1
Thread-0:running.... now:1555310552569
Thread-1:running.... now:1555310552569
========结束==time:1555310552579==count:0

应用B的样例[准备好了才结束]:

/**
 * Created by ysma on 2018/6/7.
 */
public class Test {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch cdl = new CountDownLatch(2);
        threadX driverA = new threadX(cdl);
        threadX driverB = new threadX(cdl);
        new Thread(driverA).start();
        new Thread(driverB).start();
        System.out.println("===开始==time:"+System.currentTimeMillis()+"==count:"+cdl.getCount());
        cdl.await();
        System.out.println("========结束==time:"+System.currentTimeMillis()+"==count:"+cdl.getCount());

    }

    static class threadX implements Runnable {
        private CountDownLatch cdl;
        threadX(CountDownLatch cdl){
            this.cdl = cdl;
        }

        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName()
                        + ":running.... now:"
                        + System.currentTimeMillis());
                Thread.sleep(10);
                cdl.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
===========执行结果===========
Thread-0:running.... now:1555310728080
Thread-1:running.... now:1555310728080
===开始==time:1555310728080==count:2
========结束==time:1555310728090==count:0

============================分割线==================

tips

       A:latch.countDown(); 建议放到finally语句里。
       B:对这个计数器的操作都是原子操作,同时只能有一个线程去操作这个计数器。
       C:常与CyclicBarrier伴生讨论,将在后续章节进行讲述。
       D:主要功能简述-
            public CountDownLatch(int count); //指定计数的次数,只能被设置1次[闭锁特性]
            public void countDown();          //计数器减1
            /**await(...)会一直阻塞当前线程,直到计时器的值为0,除非线程被中断*/
            public void await() throws InterruptedException   
            Public boolean await(long timeout, TimeUnit unit) //and 返回false代表计数器超时。
           E:使用了AQS的状态来代表计数count,所以CountDownLatch是基于AQS的实现不是CAS哦

==================分割线=====================

源码解读及注释

    

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class CountDownLatch {
    /**
     * Synchronization control For CountDownLatch.
     * Uses AQS state to represent count.
     */
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        /**AQS共享模式加锁 就必须实现tryAcquireShared和tryReleaseShared*/
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;//计数为0时就可以结束并解除阻塞了
        }

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {//循环执行直到cas减一成立或者计数器归零
                int c = getState();
                if (c == 0)//计数器归零 退出
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))//cas减一
                    return nextc == 0;
            }
        }
    }

    private final Sync sync;

    /**Constructs a {@code CountDownLatch} initialized with the given count.*/
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

    /**当前线程阻塞知道计数归零或者线程interrupted
     * 最终会由AbstractQueuedSynchronizer中的parkAndCheckInterrupt方法实现阻塞
     * ....LockSupport.park(this);
     * */
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    /**同上,增加了超时,timeout纳秒内计数没有归零返回false*/
    public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

    /**计数器减1*/
    public void countDown() {
        sync.releaseShared(1);
    }
}

 

© 著作权归作者所有

重城重楼
粉丝 4
博文 59
码字总数 45991
作品 0
南京
程序员
私信 提问
多线程-AQS-CyclicBarrier

1、CyclicBarrier和CountDownLatch的区别 CountDownLatch是闭锁,只能使用一次,而CyclicBarrier的计数器会重置,可以使用多次,所以CyclicBarrier能够处理更为复杂的场景; CyclicBarrier还提...

重城重楼
05/08
26
0
转载:AbstractQueuedSynchronizer的实现分析(下)

http://www.infoq.com/cn/articles/java8-abstractqueuedsynchronizer 前言 经过本系列的上半部分JDK1.8 AbstractQueuedSynchronizer的实现分析(上)的解读,相信很多读者已经对AbstractQue...

锦语冰
2016/12/02
3
0
透过CountDownLatch窥探AQS

本文来自公众号“Kahuna”,可搜索Alitaba119,欢迎关注,转载请注明出处,非常感谢 “ A synchronization aid that allows one or more threads to wait until a set of operations being ...

01/07
0
0
Java并发编程笔记之 CountDownLatch闭锁的源码分析

JUC 中倒数计数器 CountDownLatch 的使用与原理分析,当需要等待多个线程执行完毕后在做一件事情时候 CountDownLatch 是比调用线程的 join 方法更好的选择,CountDownLatch 与 线程的 join 方...

狂小白
2018/07/06
0
0
Java多线程之---用 CountDownLatch 说明 AQS 的实现原理

本文基于 jdk 1.8 。 CountDownLatch 的使用 前面的文章中说到了 volatile 以及用 volatile 来实现自旋锁,例如 java.util.concurrent.atomic 包下的工具类。但是 volatile 的使用场景毕竟有...

风的姿态
2018/06/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

java通过ServerSocket与Socket实现通信

首先说一下ServerSocket与Socket. 1.ServerSocket ServerSocket是用来监听客户端Socket连接的类,如果没有连接会一直处于等待状态. ServetSocket有三个构造方法: (1) ServerSocket(int port);...

Blueeeeeee
今天
6
0
用 Sphinx 搭建博客时,如何自定义插件?

之前有不少同学看过我的个人博客(http://python-online.cn),也根据我写的教程完成了自己个人站点的搭建。 点此:使用 Python 30分钟 教你快速搭建一个博客 为防有的同学不清楚 Sphinx ,这...

王炳明
昨天
5
0
黑客之道-40本书籍助你快速入门黑客技术免费下载

场景 黑客是一个中文词语,皆源自英文hacker,随着灰鸽子的出现,灰鸽子成为了很多假借黑客名义控制他人电脑的黑客技术,于是出现了“骇客”与"黑客"分家。2012年电影频道节目中心出品的电影...

badaoliumang
昨天
14
0
很遗憾,没有一篇文章能讲清楚线程的生命周期!

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本。 简介 大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的。 ...

彤哥读源码
昨天
15
0
jquery--DOM操作基础

本文转载于:专业的前端网站➭jquery--DOM操作基础 元素的访问 元素属性操作 获取:attr(name);$("#my").attr("src"); 设置:attr(name,value);$("#myImg").attr("src","images/1.jpg"); ......

前端老手
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部