使用:
场景1:等待driver完成后再执行其他线程(服务可用性检测)。
package mianshi.countdownlatch;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
public class Driver {
public static void main(String[] args) throws Exception {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
new Thread(new Worker(startSignal, doneSignal)).start();
}
doSomethingElse();//开启驱动
startSignal.countDown();
doneSignal.await();//等待所有线程完成
doOtherthingElse();//完成后做其他事
System.out.println(doneSignal.getCount());//0
}
static void doSomethingElse() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("driver is ok");
}
static void doOtherthingElse() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("things done");
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (Exception e) {
}
}
void doWork() {
try {
Thread.sleep((int)(Math.random()*10000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
场景2:协同作业,等待作业完成。
package mianshi.countdownlatch;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Driver2 { // ...
public static void main(String[] args) throws InterruptedException {
CountDownLatch doneSignal = new CountDownLatch(10);
ExecutorService e = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; ++i) // create and start threads
e.execute(new WorkerRunnable(doneSignal, i));
doneSignal.await(); // wait for all to finish
System.out.println(doneSignal.getCount());
e.shutdown();
}
}
class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final int i;
WorkerRunnable(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}
public void run() {
doWork(i);
doneSignal.countDown();
}
void doWork(int i) {
System.out.println(i);
}
}
场景3:实现最大并行性,模拟高并发
场景4:获取zook实例的时候,等待连接完成
public static ZooKeeper getInstance(Watcher watcher) {
ZooKeeper zk = null;
try {
CountDownLatch connectedSemaphore = new CountDownLatch(1);
boolean needWait = false;
if (watcher == null) {
needWait = true;
watcher = new Watcher() {
public void process(WatchedEvent event) {
if (KeeperState.SyncConnected == event.getState()) {
connectedSemaphore.countDown();
}
}
};
}
zk = new ZooKeeper(connectStr, sessionTimeout, watcher);
if (needWait) {
try {
connectedSemaphore.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
createChroot();
return zk;
}
CyclicBarrier例子:
中国式过马路,5人凑够数,就过,但是司机必须等到全部过去后才能过。
package mianshi.countdownlatch;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String args[]) throws Exception {
List<Person> list = new ArrayList<>();
CyclicBarrier barrier = new CyclicBarrier(5);
CountDownLatch latch = new CountDownLatch(10);
TrafficLight light = new TrafficLight(barrier, latch);
for (int i = 1; i <= 10; i++) {
list.add(new Person(light));
}
Driver3 driver = new Driver3(light);
new Thread(driver).start();
Thread t = null;
for (Person p : list) {
p.setName("p" + (list.indexOf(p) + 1));
t = new Thread(p);
t.start();
Thread.sleep(500);// 每过500ms来一个人
}
}
}
class Person implements Runnable {
private TrafficLight light;
private String name;
public Person(TrafficLight light) {
this.light = light;
}
public void setName(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name + "等红灯中.....");
light.peopleWaitRedLight();
System.out.println(name + "过马路....哒哒哒...");
}
}
class Driver3 implements Runnable {
private TrafficLight light;
public Driver3(TrafficLight light) {
this.light = light;
}
@Override
public void run() {
System.out.println("司机等红灯中...烦烦烦...");
light.driverWaitRedLight();
System.out.println("司机过马路喽...嘟嘟嘟...");
}
}
class TrafficLight {
private CyclicBarrier barrier;
private CountDownLatch latch;
public TrafficLight(CyclicBarrier barrier, CountDownLatch latch) {
this.barrier = barrier;
this.latch = latch;
}
public void driverWaitRedLight() {
try {
latch.await();
Thread.sleep(1);// 让人完全走过去
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void peopleWaitRedLight() {
try {
this.barrier.await();
System.out.println("凑够数了,大家一起闯红灯了.");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
} finally {
if (latch != null) {
latch.countDown();
}
}
}
}
面试题:
- 解释一下CountDownLatch概念?
CountDownLatch是在jdk1.5引入的,在java.util.concurrent包下,允许一个或多个线程等待直到其他线程完成操作。
CountDownLatch通过计数器来实现,初始值为线程的数量,每执行完一个线程 计数器减1,直到变成0,调用await方法的
线程才能继续执行。
- 给出一些CountDownLatch使用的例子?
1、核心服务检测
2、模拟高并发
3、zook连接
- CountDownLatch 类中主要的方法?
await 当前线程等待直到计数器为0
countDown 计数器减1
- 说说 CountDownLatch、CyclicBarrier 原理和区别
原理:
CountDownLatch:https://www.jianshu.com/p/7c7a5df5bda6
线程调用CountDownLatch await方法直到计数器减为0.
主要通过计数器,在调用CountDownLatch wait方法等时候,计数器减一,
CyclicBarrier:
再CyclicBarrier内部定义了一个Lock对象,每当一个线程调用await方法的时候,计数器减1,同时判断计数器是否为0,为0执行runable方法,重置栅栏,并唤醒所有在lock队列里面等待的线程,否则进入lock的等待队列。
区别:
CyclicBarrier强调的是n个线程相互等待,直到完成再执行任务,计数器可以重置,复用,所以叫循环栅栏。
CountDownLatch允许一个或多个线程等待直到其他线程完成操作 ,只能使用一次。
参考裁判的例子:https://aaron-han.iteye.com/blog/1591755
参考:http://www.importnew.com/15731.html
jdk源码