欢迎访问www.allbetgaming.com!

首页科技正文

绥化违章查询:同步工具类—— CountDownLatch

admin2020-08-1855

本博客系列是学习并发编程过程中的纪录总结。由于文章对照多,写的时间也对照散,以是我整理了个目录贴(传送门),利便查阅。

并发编程系列博客传送门

CountDownLatch简介

CountDownLatch是JDK并发包中提供的一个同步工具类。官方文档对这个同步工具的先容是:

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

上面的英文先容大致意思是:CountDownLatch的主要功能是让一个或者多个线程守候直到一组在其他线程中执行的操作完成。

使用列子

旁观上面的注释可能并不能直观的说明CountDownLatch的作用,下面我们通过一个简朴的列子看下CountDownLatch的使用。

场景:主人(主线程)请客人(子线程)吃晚饭,需要守候所有客人都到了之后才开饭。我们用CountDownLatch来模拟下这个场景。

public class CountDownLatchDemo {

    private static final int PERSON_COUNT = 5;

    private static final CountDownLatch c = new CountDownLatch(PERSON_COUNT);

    public static void main(String[] args) throws InterruptedException {
        System.out.println("l am master, waiting guests...");
        for (int i = 0; i < PERSON_COUNT; i++) {
            int finalI = i;
            new Thread(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+" l am person["+ finalI +"]");
                    TimeUnit.MILLISECONDS.sleep(500);
                    //System.out.println(Thread.currentThread().getName()+" count:"+c.getCount());
                    c.countDown();
                }
            }).start();
        }
        c.await();
        System.out.println("all guests get, begin dinner...");
    }

}

上面的列子中,主人(master线程)请了5个客人用饭,每个客人到了之后会将CountDownLatch的值减一,主人(master)会一直守候所有客人到来,最后输出”开饭“。

CountDownLatch的使用方式很简朴,下面来看下它的实现原理。

原理剖析

首先我们先看下CountDownLatch主要的API

- getCount():获取当前count的值。
- wait():让当前线程在此CountDownLatch工具上守候,可以中止。与notify()、notifyAll()方式对应。
- await():让当前线程守候此CountDownLatch工具的count变为0,可以中止。
- await(timeout,TimeUnit):让当前线程守候此CountDownLatch工具的count变为0,可以超时、可以中止。
- countDown():使此CountDownLatch工具的count值减1(无论执行多少次,count最小值为0)。

下面我们看下详细API的源代码

组织函数

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

在构建CountDownLatch工具时需要传入一个int型的初始值,这个值就是计数器的初始值。从上面的代码中可以看出,建立CountDownLatch是new了一个Sync工具。

private static final class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 4982264981922014374L;

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

    int getCount() {
        return getState();
    }

    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }

    protected boolean tryReleaseShared(int releases) {
        // Decrement count; signal when transition to zero
        for (;;) {
            int c = getState();
            if (c == 0)
                return false;
            int nextc = c-1;
            if (compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }
}

Sync工具是基于AQS机制实现的,自己实现了tryAcquireSharedtryReleaseShared方式。

await方式


 public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

挪用await方式实在是挪用了AQS的acquireSharedInterruptibly方式。

 public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}

acquireSharedInterruptibly中先判断了下当前线程有没有被中止,若是线程已经被中止了,直接抛出中止异常。否则进入doAcquireSharedInterruptibly

private void doAcquireSharedInterruptibly(int arg) throws InterruptedException {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

doAcquireSharedInterruptibly的处置逻辑是先判断行列中是否只有当前线程,若是只有当前线程的先实验获取下资源,若是获取资源乐成就直接返回了。获取资源不乐成就判断下是否要park当前线程,若是需要park当前线程,
那么当前线程就进入waiting状态。否则在for循环中一直执行上面的逻辑。

countDown方式

public void countDown() {
    sync.releaseShared(1);
}

熟悉AQS机制的会知道上面的代码实在也是调的AQS的releaseSharedreleaseShared的方式会调到Sync中的tryReleaseShared

protected boolean tryReleaseShared(int releases) {
    // Decrement count; signal when transition to zero
    for (;;) {
        int c = getState();
        if (c == 0)
            return false;
        int nextc = c-1;
        if (compareAndSetState(c, nextc))
            return nextc == 0;
    }
}

上面的代码逻辑很简朴:status的值是0的话就返回true,否则返回false。返回true的话,就会叫醒AQS行列中所有壅闭的线程。

使用场景

  • 场景一:将义务分割成多个子义务,每个子义务由单个线程去完成,等所有线程完成后再将效果汇总。(MapReduce)这种场景下,CountDoenLatch作为一个完成信号来使用。
  • 场景二:多个线程等到,一直等到某个条件发生。好比多个赛跑运动员都做好了准备,就守候裁判手中的发令枪响。这种场景下,就可以将CountdownLatch的初始值设置成1。

简朴总结

  • CountDownLatch的初始值不能重置,只能削减不能增添,最多削减到0;
  • CountDownLatch计数值没削减到0之前,挪用await方式可能会让挪用线程进组一个壅闭行列,守候计数值减小到0;
  • 挪用countDown方式会让计数值每次都减小1,然则最多削减到0。当CountDownLatch的计数值削减到0的时刻,会叫醒所有在壅闭行列中的线程。
,

Sunbet

Sunbet展望2019年,将用完善的服务体系,创新的技术应用,雄厚的资金实力,贴心的服务品质,成为每位申博会员、代理的首选平台。

转载声明:本站发布文章及版权归原作者所有,转载本站文章请注明文章来源!

本文链接:https://www.juneview.com/post/716.html

网友评论

1条评论
  • 2020-08-18 00:15:05

    欧博官网欢迎进入欧博官网(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。这个,很值

最新评论

  • 环球UG注册 09/18 说:

    欧博allbet网址欢迎进入欧博allbet网址(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。感觉还可以,继续追。

  • 环球UG注册 09/18 说:

    欧博allbet网址欢迎进入欧博allbet网址(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。感觉还可以,继续追。

  • 皇冠体育APP 09/18 说:

    欧博开户网址欢迎进入欧博开户网址(Allbet Gaming):www.aLLbetgame.us,欧博网址开放会员注册、代理开户、电脑客户端下载、苹果安卓下载等业务。下笔如有神

  • UG环球网址 09/18 说:

    AllbetGmaing电脑版下载欢迎进入AllbetGmaing电脑版下载(www.aLLbetgame.us):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。反正我跪了

  • UG环球客户端 09/18 说:

    Allbet Gmaing欢迎进入欧博Allbet官网(www.aLLbetgame.us):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。我也来看

  • UG环球官网 09/17 说:

    ALLBET官网娱乐平台开户欢迎进入ALLBET官网娱乐平台开户:www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。有趣

  • 皇冠APP下载 09/17 说:

    AllbetGmaing手机版下载欢迎进入AllbetGmaing手机版下载(www.aLLbetgame.us):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。想交读友

  • UG环球手机版下载 09/17 说:

    欧博注册欢迎进入欧博注册(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。好多人都看啊