菜单

Java多线程编制程序笔记之CountDownLatch

2019年5月17日 - sqlite

直译过来正是倒计数(CountDown)门闩(Latch)。倒计数不用说,门闩的乐趣看名称就能够想到其意义正是掣肘前进。在那边就是指
CountDownLatch.await() 方法在倒计数为0从前会阻塞当前线程。
CountDownLatch是二个联手扶助类,在成就一组正在其余线程中推行的操作此前,它同意1个或七个线程一直守候。
CountDownLatch 的效果和 Thread.join()
方法类似,可用以1组线程和此外1组线程的通力合营。举例,主线程在做1项职业在此之前必要一雨后春笋的备选干活,唯有那个预备干活都形成,主线程技术一连它的职业。那么些预备干活竞相独立,所以能够并发施行以增速。在那几个场景下就足以应用
CountDownLatch 协调线程之间的调节了。在直接成立线程的时代(Java 5.0
此前),我们得以采纳 Thread.join()。在 JUC
出现后,因为线程池中的线程不可能直接被引用,所以就亟须选择 CountDownLatch
了。
CountDownLatch类是一个联合计数器,构造时传出int参数,该参数正是计数器的始发值,每调用叁次countDown()方法,计数器减壹,计数器大于0
时,await()方法会阻塞程序继续实行。
CountDownLatch可以当作是三个倒计数的锁存器,当计数减至0时接触特定的轩然大波。利用这种特征,能够让主线程等待子线程的完工。
上面以2个模仿运动员比试的例子加以证实。
CountDownLatch的一个不行优秀的行使场景是:有贰个任务想要往下试行,但不能不要等到任何的职分推行达成后技巧够再三再四往下执行。假诺大家以此想要继续往下试行的职务调用二个CountDownLatch对象的await()方法,其余的天职施行完自身的天职后调用同3个CountDownLatch对象上的countDown()方法,那么些调用await()方法的任务将一直不通等待,直到这几个CountDownLatch对象的计数值减到0结束。

本篇聊聊同步帮忙类CountDownLatch,涉及内容故事JDK7。

CountDownLatch函数列表

1.概述
CountDownLatch允许3个大概四个线程一向等候,直到一组其余操作推行到位。在动用CountDownLatch时,需求钦命1个整数值,此值是线程将要等待的操作数。当有些线程为了要施行那一个操作而等待时,须求调用await方法。await方法让线程进入休眠状态直到全数等待的操作完成收尾。当等待的有些操作实施到位,它选拔countDown方法来压缩CountDownLatch类的个中计数器。当在那之中计数器递减为0时,CountDownLatch会唤醒全数调用await方法而休眠的线程们。

CountDownLatch(int count)
构造一个用给定计数初始化的 CountDownLatch。
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
void await()
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。
boolean await(long timeout, TimeUnit unit)
// 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
void countDown()
// 返回当前计数。
long getCount()
// 返回标识此锁存器及其状态的字符串。
String toString()

贰.选择样例
上边代码演示了CountDownLatch轻松使用。演示的气象是七人选手参加跑步比赛,发令枪打响后,多少个放大计时器开首各自计时,直到全数选手都达到终点。

CountDownLatch数据结构 CountDownLatch的UML类图如下:

public class CountDownLatchDemo {
    public static void main(String[] args) {
        Timer timer = new Timer(5);
        new Thread(timer).start();

        for (int athleteNo = 0; athleteNo < 5; athleteNo++) {
            new Thread(new Athlete(timer, "athlete" + athleteNo)).start();
        }
    }
}

class Timer implements Runnable {
    CountDownLatch timerController;

    public Timer(int numOfAthlete) {
        this.timerController = new CountDownLatch(numOfAthlete);
    }

    public void recordResult(String athleteName) {
        System.out.println(athleteName + " has arrived");
        timerController.countDown();
        System.out.println("There are " + timerController.getCount() + " athletes did not reach the end");
    }

    @Override
    public void run() {
        try {
            System.out.println("Start...");
            timerController.await();
            System.out.println("All the athletes have arrived");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Athlete implements Runnable {
    Timer timer;
    String athleteName;

    public Athlete(Timer timer, String athleteName) {
        this.timer = timer;
        this.athleteName = athleteName;
    }

    @Override
    public void run() {
        try {
            System.out.println(athleteName + " start running");
            long duration = (long) (Math.random() * 10);
            Thread.sleep(duration * 1000);
            timer.recordResult(athleteName);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

图片 1

输出结果如下所示:

CountDownLatch的数据结构相当粗略,它是经过”共享锁”达成的。它含有了sync对象,sync是Sync类型。Sync是实例类,它连续于AQS。

Start...
athlete0 start running
athlete1 start running
athlete2 start running
athlete3 start running
athlete4 start running
athlete0 has arrived
There are 4 athletes did not reach the end
athlete3 has arrived
There are 3 athletes did not reach the end
athlete2 has arrived
athlete1 has arrived
There are 1 athletes did not reach the end
There are 2 athletes did not reach the end
athlete4 has arrived
There are 0 athletes did not reach the end
All the athletes have arrived

CountDownLatch的运用示例 下边通过CountDownLatch实现:”主线程”等待”伍个子线程”全体都变成”钦命的行事(休眠一千ms)”之后,再持续运转。

3.创构造方法
CountDownLatch(int
count)构造一个点名计数的CountDownLatch,count为线程将在等待的操作数。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

public class CountDownLatchTest1 {

 private static int LATCH_SIZE = 5;
 private static CountDownLatch doneSignal;
 public static void main(String[] args) {

  try {
   doneSignal = new CountDownLatch(LATCH_SIZE);

   // 新建5个任务
   for(int i=0; i<LATCH_SIZE; i++)
    new InnerThread().start();

   System.out.println("main await begin.");
   // "主线程"等待线程池中5个任务的完成
   doneSignal.await();

   System.out.println("main await finished.");
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }

 static class InnerThread extends Thread{
  public void run() {
   try {
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + " sleep 1000ms.");
    // 将CountDownLatch的数值减1
    doneSignal.countDown();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
 }
}

四.常用艺术
4.1 await()
调用await方法后,使方今线程在锁存器(内部计数器)倒计数至零事先一贯等待,进入休眠状态,除非线程被中断。要是当前计数递减为零,则此办法立即回去,继续施行。

运作结果:

4.2 await(long timeout, TimeUnit unit)
调用await方法后,使如今线程在锁存器(内部计数器)倒计数至零此前一直守候,进入休眠状态,除非线程被
中断或高于了点名的等候时间。要是当前计数为零,则此格局马上回去true值。

main await begin.
Thread-0 sleep 1000ms.
Thread-2 sleep 1000ms.
Thread-1 sleep 1000ms.
Thread-4 sleep 1000ms.
Thread-3 sleep 1000ms.
main await finished.

4.3 acountDown()
acountDown方法递减锁存器的计数,固然计数达到零,则释放具备等待的线程。借使当前计数超越零,则将计数减少。假诺新的计数为零,出于线程调节目标,将重新启用全数的等候线程。

结果表明:主线程通过doneSignal.await()等待别的线程将doneSignal递减至0。别的的多少个InnerThread线程,每三个都通过doneSignal.countDown()将doneSignal的值减1;当doneSignal为0时,main被唤醒后继续试行。

4.4 getCount()
调用此情势后,重临当前计数,即还未成功的操作数,此方法一般用于调节和测试和测试。

PS:CountDownLatch和CyclicBarrier的区别: (一)
CountDownLatch的效益是允许1或N个线程等待别的线程完毕实行;而CyclicBarrier则是允许N个线程相互等待。
(2)
CountDownLatch的计数器不能被复位;CyclicBarrier的计数器能够被重新初始化后使用,因而它被喻为是循环的barrier。

您大概感兴趣的稿子:

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图