CountDownLatch类

基本概念

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

一种同步辅助工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成


原理及缺点

A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier.

CountDownLatch是用给定的计数初始化的。由于调用countDown()方法,await方法会一直阻塞,直到当前计数达到零,然后释放所有等待的线程,并立即返回任何后续的await调用。这是一种一次性现象——无法重置计数。如果需要重置计数的版本,请考虑使用CyclicBarrier


多功能使用

A CountDownLatch is a versatile synchronization tool and can be used for a number of purposes. A CountDownLatch initialized with a count of one serves as a simple on/off latch, or gate: all threads invoking await wait at the gate until it is opened by a thread invoking countDown(). A CountDownLatch initialized to N can be used to make one thread wait until N threads have completed some action, or some action has been completed N times.

CountDownLatch是一种多功能同步工具,可用于多种目的。以计数1初始化的CountDownLatch用作简单的开/关闩锁或门:所有调用的线程等待等待在门上等待,直到它被调用countDown()的线程打开。初始化为N的CountDownLatch可用于制作一个线程,直到N个线程完成某些操作,或者某些操作已完成N次

经典用法1
某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为new CountDownLatch(n),每当一个任务线程执行完毕,就将计数器减1 countdownLatch.countDown(),当计数器的值变为0时,在CountDownLatch上await()的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行

经典用法2
实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计算器初始化为1,多个线程在开始执行任务前首先countdownlatch.await(),当主线程调用countDown()时,计数器变为0,多个线程同时被唤醒


非countDown线程处理

A useful property of a CountDownLatch is that it doesn't require that threads calling countDown wait for the count to reach zero before proceeding, it simply prevents any thread from proceeding past an await until all threads could pass.

CountDownLatch的一个有用属性是它不要求调用countDown的线程在继续之前等待计数达到零,它只是阻止任何线程经过等待,直到所有线程都可以通过


构造函数及常用方法详解
说明
CountDownLatch(int count) 构造一个CountDownLatch使用给定计数初始化的对象
count 指CountDownLatch需调用countDown()的次数,才可唤醒await()的线程,不可为负数!
public void await() 使当前线程等待直到闩锁倒计时为零,除非线程被中断
public boolean await(long timeout, TimeUnit unit) 使当前线程等待直到闩锁倒计时为零,除非线程被中断,或者指定的等待时间已过
public void countDown() 递减锁存器的计数,如果计数达到零,则释放所有等待的线程
public long getCount() 返回当前计数

public boolean await(long timeout, TimeUnit unit)
如果当前计数为零,则此方法立即返回值true

如果当前计数大于零,则当前线程出于线程调度目的而被禁用并处于休眠状态,直到发生以下三种情况之一:

  • 由于countDown()方法的调用,计数达到零
  • 其他一些线程中断当前线程
  • 指定的等待时间已过

如果计数达到零,则该方法返回值true

如果当前线程:

  • 在进入此方法时设置其中断状态;或者
  • 等待时被打断
    然后InterruptedException被抛出并清除当前线程的中断状态

如果指定的等待时间过去,则false 返回该值。如果时间小于或等于零,则该方法根本不会等待

timeout - 最长等待时间
unit-timeout参数的时间单位

public void countDown()
如果当前计数大于零,则递减。如果新计数为零,则为线程调度目的重新启用所有等待线程
如果当前计数为零,则什么也不会发生


代码实现
package com.itheima.mycountdownlatch;

import java.util.concurrent.CountDownLatch;

public class ChileThread1 extends Thread {

    private CountDownLatch countDownLatch;
    public ChileThread1(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        //1.吃饺子
        for (int i = 1; i <= 10; i++) {
            System.out.println(getName() + "在吃第" + i + "个饺子");
        }
        //2.吃完说一声
        //每一次countDown方法的时候,就让计数器-1
        countDownLatch.countDown();
    }
}
package com.itheima.mycountdownlatch;

import java.util.concurrent.CountDownLatch;

public class ChileThread2 extends Thread {

    private CountDownLatch countDownLatch;
    public ChileThread2(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }
    @Override
    public void run() {
        //1.吃饺子
        for (int i = 1; i <= 15; i++) {
            System.out.println(getName() + "在吃第" + i + "个饺子");
        }
        //2.吃完说一声
        //每一次countDown方法的时候,就让计数器-1
        countDownLatch.countDown();
    }
}
package com.itheima.mycountdownlatch;

import java.util.concurrent.CountDownLatch;

public class MotherThread extends Thread {
    private CountDownLatch countDownLatch;
    public MotherThread(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        //1.等待
        try {
            //当计数器变成0的时候,会自动唤醒这里等待的线程。
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //2.收拾碗筷
        System.out.println("妈妈在收拾碗筷");
    }
}
package com.itheima.mycountdownlatch;

import java.util.concurrent.CountDownLatch;

public class MyCountDownLatchDemo {
    public static void main(String[] args) {
        //1.创建CountDownLatch的对象,需要传递给3个线程。
        //在底层就定义了一个计数器,此时计数器的值就是2
        CountDownLatch countDownLatch = new CountDownLatch(2);
        //2.创建3个线程对象并开启他们。
        MotherThread motherThread = new MotherThread(countDownLatch);
        motherThread.start();

        ChileThread1 t1 = new ChileThread1(countDownLatch);
        t1.setName("小明");

        ChileThread2 t2 = new ChileThread2(countDownLatch);
        t2.setName("小红");

        t1.start();
        t2.start();
    }
}

你可能感兴趣的:(CountDownLatch类)