CountDownLatch是一个同步辅助类,使用时可以当做倒计时计数器来使用,创建对象时通过构造方法设置初始值,调用CountDownLatch对象的await()方法则处于等待状态,调用countDown()方法就将计数器减1,当计数到达0时,则所有等待者或单个等待者开始执行。
**构造方法摘要**
CountDownLatch(int count)
构造一个用给定计数初始化的 CountDownLatch。
**方法摘要**
void await()
使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
boolean await(long timeout, TimeUnit unit)
使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的 等待时间。
void countDown()
递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
long getCount()
返回当前计数。
String toString()
返回标识此锁存器及其状态的字符串。
如下代码模拟吃货比赛,有十名吃货选手进行吃包子的比赛,设置一个开始计数锁,eatInitcountDownLatch ,初始值是1,比赛开始时,将调用countDown()方法来将计数器减一,选手线程中的await()方法感知到计数器已经到达0,就开始比赛, 设置一个结束计数锁,eatTotalcountDownLatch ,初始值是10,表明有10名选手进行比赛,一旦有一个选手吃完了所有的包子(30个),选手线程就调用eatTotalcountDownLatch .countDown()方法来将总数计数器减一,主类(比赛类)中的eatTotalcountDownLatch.await()方法一直处于阻塞状态,直到所有的选手都完成比赛,将总数计数器的值减为0时,出发比赛结束的操作。
CountDownLatchDemo.java 比赛主类
/**
* 比赛
* @author sunhf
* @category runnable
* */
package com.sun.comcurrent.countDownLatch.demo;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchDemo
{
public static final int FOODIE_COUNT = 10;
public static void main(String[] args) throws InterruptedException
{
// 定义一个线程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 设置开始计数锁
CountDownLatch eatInitcountDownLatch = new CountDownLatch(1);
// 设置结束计数锁
CountDownLatch eatTotalcountDownLatch = new CountDownLatch(10);
Foodie[] foodies = new Foodie[FOODIE_COUNT];
for (int i = 0; i < FOODIE_COUNT; i++)
{
foodies[i] = new Foodie("吃货:" + i, eatInitcountDownLatch, eatTotalcountDownLatch);
}
System.out.println("各位吃货选手准备!");
for (Foodie f : foodies)
executorService.execute(f);//启动选手线程
//无用 只是为了体现效果 休息6秒
Thread.sleep(6000);
System.out.println("比赛开始!");
//开始计数锁 减一
eatInitcountDownLatch.countDown();
try
{
//结束计数锁 处于阻塞状态,等待计数变为0 执行
eatTotalcountDownLatch.await();
//无用 只是为了体现效果 休息6秒
Thread.sleep(20);
} catch (InterruptedException e)
{
e.printStackTrace();
} finally
{
System.out.println("比赛结束了!");
}
executorService.shutdown();
}
}
Foodie.java 选手线程类:
package com.sun.comcurrent.countDownLatch.demo;
import java.util.concurrent.CountDownLatch;
/**
* 吃货
*
* @author sunhf
* @category runnable
* */
public class Foodie implements Runnable
{
private String name;
private CountDownLatch foodieInitCount;
private CountDownLatch foodieTotalCount;
public Foodie(String name, CountDownLatch foodieInitCount, CountDownLatch foodieTotalCount)
{
this.name = name;
this.foodieInitCount = foodieInitCount;
this.foodieTotalCount = foodieTotalCount;
}
@Override
public void run()
{
try
{
System.out.println( name + " 准备好了");
//此时线程在阻塞状态,等待倒数锁到达0
foodieInitCount.await();
Long eatTime =(long) (Math.random() * 10000);
Thread.sleep(eatTime);
System.out.println(name +
" 玩命吃了30个包子,使用了 " + eatTime + " 秒");
} catch (InterruptedException e)
{
e.printStackTrace();
} finally
{
foodieTotalCount.countDown();//执行完毕,递减锁的计数器
System.out.println( name + " 去吐了o(╯□╰)o");
}
}
}
执行结果:
各位吃货选手准备!
吃货:0 准备好了
吃货:2 准备好了
吃货:1 准备好了
吃货:4 准备好了
吃货:6 准备好了
吃货:3 准备好了
吃货:8 准备好了
吃货:5 准备好了
吃货:7 准备好了
吃货:9 准备好了
比赛开始!
吃货:5 玩命吃了30个包子,使用了 918 秒
吃货:5 去吐了........o(╯□╰)o
吃货:0 玩命吃了30个包子,使用了 1175 秒
吃货:0 去吐了........o(╯□╰)o
吃货:1 玩命吃了30个包子,使用了 1364 秒
吃货:1 去吐了........o(╯□╰)o
吃货:4 玩命吃了30个包子,使用了 1483 秒
吃货:4 去吐了........o(╯□╰)o
吃货:3 玩命吃了30个包子,使用了 2691 秒
吃货:3 去吐了........o(╯□╰)o
吃货:6 玩命吃了30个包子,使用了 3582 秒
吃货:6 去吐了........o(╯□╰)o
吃货:7 玩命吃了30个包子,使用了 3920 秒
吃货:7 去吐了........o(╯□╰)o
吃货:2 玩命吃了30个包子,使用了 6177 秒
吃货:2 去吐了........o(╯□╰)o
吃货:9 玩命吃了30个包子,使用了 7250 秒
吃货:9 去吐了........o(╯□╰)o
吃货:8 玩命吃了30个包子,使用了 7915 秒
吃货:8 去吐了........o(╯□╰)o
比赛结束了!选手们 还在吐....o(╯□╰)o