zoukankan      html  css  js  c++  java
  • Java并发基础-栅栏(CountDownLatch)与闭锁(CyclicBarrier)

    1. 闭锁CountDownLatch

    闭锁CountDownLatch用于线程间的同步,它可以使得一个或者多个线程等待其它线程中的某些操作完成。它有一个int类型的属性count,当某个线程调用CountDownLatch对象的await方法时,将会阻塞,直到count的值变成0;count值可以通过它的countDown的方法进行减1。 count的值在构造方法中进行指定。

    注意count的值不可以重设,因此当count的值变成0后,CountDownLatch就不再起作用了,此时再调用它的await方法将会直接返回。也就是说,对它的重复使用是没有任何意义的。

    它可以使用在以下场景:

    当count的值为1时,可以作为一个开关,所有调用它的await方法的线程都一起等待,直到开关被某个其它线程打开;

    当count的值为n时,可以使得一个或者多个线程等待其它n个线程完成了某些处理,或者某个线程执行了n次某项操作;

    典型的用法如:将一个计算过程细分成n个子计算,主线程调用CountDownLatch的await方法等待子任务计算完成;而n个子线程处理每个子任务;当每个子任务执行完成后调用countDown方法。这样子任务计算完成时主线程就可以继续往下执行了。

    注意:CountDownLatch本身是线程安全的,因此对它的方法的调用不需要再使用其它的同步机制。

    1.1 示例

    假设要主线程要等待其它一组线程执行完某个操作再继续执行,可以使用以下方式:

    直接运行,执行结果如下:

    可以看到:主线程调用latch.await方法后即等待;当所有被提交的Work作业执行完latch.countDown后,主线程继续执行,而不用等到所有子线程全部完成。

    如果将latch.countDown()方法放在每个子线程的最后,那么就意味着主线程需要等待所有子线程执行完成了。这个时候就与线程池中使用Future中的get方法类似。

    因此,在线程间的协作上,CountDownLatch可以进行更加精细的控制:某个线程可以依赖于其它线程执行部分后马上执行,而不用等待依赖的线程全部执行完成后再执行!

    1.2 CountDownLatch方法说明

    闭锁主要包含以下方法:

    a. await() throws InterruptedException

    如果count的值为0,那么该方法将直接返回;否则当前线程将会阻塞直到闭锁的count值变成0或者当前线程被中断。

    b. boolean await(long timeout, TimeUnit unit) throws InterruptedException

    如果count的值为0,那么该方法直接返回,否则将会阻塞直到闭锁的count变成0或者当前线程被中断或者超时时间到;当count变成0时返回True;否则如果超时时间到且未变成0则返回False。

    c. countDown()

    如果当前值已经是0则不会做任何事情; 否则将count的值减1;如果新值变成0的时候将会唤醒所有等待的线程;

    d. long getCount()

    返回当前的count值。

    2.栅栏CyclicBarrier

    栅栏是一种多线程之间的同步机制,它允许多个线程等待彼此直到每个线程都到达某个位置。它的名称中含有cyclic是因为它可以重复使用。

    如:有一张门有N把钥匙,需要N把钥匙组合到一起才能开门,大家商量好同时从不同地方向那张门赶去,先到的人必须要等待所有人都到达后才能打开门并进入。

    2.1 使用示例

    执行结果:

    从结果中可以看出:直到三个线程都打印了第一条消息后,所有线程才继续执行。

    注意:通过构造函数,可以传入需要等待的参与者个数。如果调用await的线程达到参与者个数,那么所有的参与者都会继续往下执行;即使参与者个数大于指定的个数。

    2.2CyclicBarrier的使用

    主要是await与reset方法

    a. await

    阻塞当前线程,直到等待所有的参与者线程都调用了这个方法。当被中断时抛出对应异常。它也可以指定超时时间,在超时时间到后直接返回。

    b. reset

    重置栅栏到初始化状态,使得它可以继续被使用。

    3.栅栏与闭锁的区别

    经过以上分析,栅栏与闭锁主要有以下区别:

    闭锁不可以重复使用,而栅栏提供了reset方法,可以重复使用。

    使用场景上:闭锁主要使用在一个或者多个线程等待某个条件的发生,这个条件一般是由其它非等待线程来进行更新;而栅栏多个线程等待的条件就是这些线程都运行到某个位置,而不能由这些线程以外的其它线程来进行控制。

    注意实际上除了重复使用外,闭锁也可以使用在栅栏的场景中,每个线程在调用闭锁的await方法前都先调用countDown(),那与直接调用栅栏的await方法可以达到同样的效果。

  • 相关阅读:
    JS BOM对象 History对象 Location对象
    JS 字符串对象 数组对象 函数对象 函数作用域
    JS 引入方式 基本数据类型 运算符 控制语句 循环 异常
    Pycharm Html CSS JS 快捷方式创建元素
    CSS 内外边距 float positio属性
    CSS 颜色 字体 背景 文本 边框 列表 display属性
    【Android】RxJava的使用(三)转换——map、flatMap
    【Android】RxJava的使用(二)Action
    【Android】RxJava的使用(一)基本用法
    【Android】Retrofit 2.0 的使用
  • 原文地址:https://www.cnblogs.com/yuandluck/p/9510115.html
Copyright © 2011-2022 走看看