zoukankan      html  css  js  c++  java
  • 同步计数器 CountDownLatch

    CountDownLatch 是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行.

    CountDownLatch 是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

     

    主要方法有:

    • CountDownLatch (int count),构造一个用给定计数器初始化的CountDownLatch。构造器中的计数值(count)实际上就是闭锁需要等待的线程数量。这个值只能被设置一次,而且CountDownLatch没有提供任何机制去重新设置这个计数值
    • void await (),使当前线程在锁存器倒计数至0之前一直等待,除非线程被中断。
    • boolean await (long timeout, TimeUnit unit),使当前线程在锁存器,倒计数至0之前一直等待,除非线程被中断或超出了指定的等待时间。
    • void countDwon (),递减锁存器的计数,如果计数达到0,则释放所有等待的线程。
    • long getCount (),返回当前计数。

    使用场景:

    在一些应用场景中,需要等待某个条件达到要求后才能做后面的事情;同时当线程都完成后也会触发事件,以便进行后面操作。

    CountDownLatch的countDown() 和 await(),前者主要倒数一次,后者是等待倒数到0,如果没有到0,就只有阻塞等待了。

    • 应用场景1:开5个多线程去下载,当5个线程都执行完了,才算下载成功。
    • 应用场景2:当用户多文件上传时,可以采用多线程上传,当多个文件都上传成功时,才算真正的上传成功。
    • 实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。
    • 开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。
    • 死锁检测:一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。
     1 public class Demo {
     2 
     3     public static void main(String[] args) throws Exception {
     4 
     5         CountDownLatch latch = new CountDownLatch(3);
     6         Worker worker1 = new Worker("xiao ming", latch);
     7         Worker worker2 = new Worker("xiao hong", latch);
     8         Worker worker3 = new Worker("xiao wang", latch);
     9 
    10         worker1.start();
    11         worker2.start();
    12         worker3.start();
    13         
    14         latch.await();
    15         
    16         System.out.println("Main Thread End.");
    17     }
    18 
    19     static class Worker extends Thread {
    20 
    21         private String workerName;
    22         private CountDownLatch latch;
    23 
    24         public Worker(String workerName, CountDownLatch latch) {
    25 
    26             this.workerName = workerName;
    27             this.latch = latch;
    28         }
    29 
    30         @Override
    31         public void run() {
    32 
    33             try {
    34                 System.out.println("Worker:" + workerName + " is begin.");
    35                 Thread.sleep(1000L);
    36                 System.out.println("Worker:" + workerName + " is end.");
    37             } catch (Exception e) {
    38                 e.printStackTrace();
    39             }
    40             latch.countDown();
    41         }
    42     }
    43 }

    输出:

    1 Worker:xiao ming is begin.
    2 Worker:xiao hong is begin.
    3 Worker:xiao wang is begin.
    4 Worker:xiao ming is end.
    5 Worker:xiao wang is end.
    6 Worker:xiao hong is end.
    7 Main Thread End.

    CountDownLatch 的实现原理:

    CountDownLatch 的核心实现机制利用 AbstractQueuedSynchronizer 简称“AQS”的 state状态来实现Count的阻塞机制。

     1 public class CountDownLattch {
     2 
     3     /**
     4      *CountDownLatch 的核心实现机制利用 AbstractQueuedSynchronizer 简称“AQS”的 state状态来实现Count的阻塞机制
     5      */
     6 
     7     private static final class Sync extends AbstractQueuedSynchronizer {
     8 
     9         Sync(int count) {
    10             setState(count);
    11         }
    12 
    13         int getCount() {
    14             return getState();
    15         }
    16 
    17         protected int tryAcquireShared(int acquires) {
    18             return (getState() == 0) ? 1 : -1;
    19         }
    20 
    21         protected boolean tryReleaseShared(int releases) {
    22             // 覆盖"AQS"的释放状态方式,实现自己的逻辑,来消减count的线程数
    23             for(;;) {
    24 
    25                 int c = getState();
    26                 if (c == 0)
    27                     return false;
    28 
    29                 int nextc = c - 1;
    30                 if (compareAndSetState(c, nextc))
    31                     return nextc == 0;
    32             }
    33         }
    34 
    35     }
    36 
    37     private final Sync sync;
    38     // 利用"AQS"的state状态,来标示线程的count的数量
    39 
    40     public CountDownLat(int count) {
    41         this.sync = new Sync(count);
    42     }
    43 
    44     // 利用"AQS"获得一个共享模式下的完成状态
    45     public void await() throws InterruptedException {
    46         sync.acquireSharedInterruptibly(1);
    47     }
    48 
    49     // 利用"AQS"获得一个共享模式下的完成状态,超出了指定的等待时间
    50     public void await(int timeout, TimeUnit unit) throws InterruptedException {
    51         sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    52     }
    53 
    54     // 利用"AQS"在共享模式下释放状态也就是数字减一
    55     public void countDown() {
    56         sync.releaseShared(1);
    57     }
    58 
    59     // 调用"AQS"返回当前计数
    60     public long getCount() {
    61         return sync.getCount();
    62     }
    63 
    64     ...
    65 }
  • 相关阅读:
    redis-单线程为什么快
    redis-数据结构
    http-状态码
    事件绑定完整版2016/4/21
    焦点事件2016、4、21
    ++
    Bom2016/4/21
    添加以及删除className
    getByClassName2016/4/21
    动态添加
  • 原文地址:https://www.cnblogs.com/CharlesGrant/p/9359180.html
Copyright © 2011-2022 走看看