Java并发编程(一) CountDownLatch

Java并发编程(一) CountDownLatch

博客分类: JDK
Java Concurrent并发CountDownLatch多线程
介绍

CountDownLatch是JDK5引入的一个新的线程辅助类,用于帮助开发人员”比较精确"的控制线程状态。CountDownLatch这个类内置了一个锁计数器,这个计数器由新建这个类的实例时指定,每调用countDown()方法一次,计数器的数字减一,当计数器为零时,所有的等待线程被释放并执行,否则这些线程是处于等待状态。

这个类在两种典型的场合下可以用得到。

第一种场合是若干个线程必须等待一个事件或者一些动作发生后才开始执行。比如,博尔特和其他7位在百米赛场上的选手必须等到发令枪响后才可以起跑,最后一位选手冲过终点时,百米跑比赛结束。这种情况下需要用参数1来初始化。

第二种场合是某件事情或者动作必须等到所有的线程都执行完后才发生执行。比如装配汽车的时候,4个工人装配4个轮子,只有4个轮子都被安装好后,流水线才能让这辆汽车进入下一个装配环节。这种情况下,用参数4来初始化。当然,这种情况,也可以用CyclicBarrier类来控制。

百米飞人大战

首先用代码模拟第一种场合。在Player类中有一个锁,让运动员处于等待状态。只有等一声发令枪响后,运动员才可以起跑。latch.await()方法正是起到了这个效果。Player中run1私有函数让线程休眠10秒钟内的一个随即时间,模拟运动员在跑的过程中,跑完后,运动员抵达终点。

在main函数中,新建一个CountDownLatch,并且设置计算器为1。接着新建一个可以同时运行8个线程的线程池-- 模拟赛道,通过调用ExecuteService.execute()函数,让所有的运动员都进入这个赛道。这个时候,计数器的值为1,所有的线程是处于等待状态。OK,接下来,调用latch.countDown(),让锁计数器为零。ExecutorService中的8个线程同时启动,所有的运动员起跑。 最后,ExecutorService.shutdown()函数会等待线程池中的8个线程全部执行完后,关闭线程池,--- 比赛结束。
Java代码 收藏代码
class Player implements Runnable {
private String name;
private CountDownLatch latch;

public Player(String name, CountDownLatch latch) {
super();
this.name = name;
this.latch = latch;
}

@Override
public void run() {
try {
latch.await();
run1();
System.out.format("Player %s reaches the endponit.%n", name);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

private void run1() throws InterruptedException {
Thread.sleep(new Random().nextInt(10000));
}

public static void main(String args[]) {
CountDownLatch latch = new CountDownLatch(1);
ExecutorService executor = Executors.newFixedThreadPool(8);
String players[] = { "Bolt", "Robles", "Liu Xiang", "Johnson", "Louis", "Gatlin", "Green", "Robert" };
for (int i = 0; i < 8; i++)
executor.execute(new Player(players[i], latch));
latch.countDown();
executor.shutdown();
}
}

装配汽车轮子

假设有4个工人在汽车生产流水线上同时装配一辆汽车上的4个轮子,因为每个工人装配轮子的速度会不一样,在汽车进入下一个作业环节前,生产流水线必须知道这辆汽车的4个轮子已经被装配好。首先设置计算器为4, 当一个工人把轮子装好后,按下按钮,让计数器减一,计数器的值变成3,最后,4个工人全部按下按钮后,计数器的值变成零。一旦计数器为零,生产线的控制程序让这辆车,进入下一个装配作业环节。
先看一下Worker类,代表一个可以安装车轮的工人,为了能明确的表示一个车轮,这里车轮被抽象成一个数字,用id代表。Worker.run()方法调用marshalTyre()私有成员函数 ------代表装配轮子,只不过是让该线程休眠了60s内的一个随机时间。实际上,该方法是主要的业务代码,完成了轮子的装配工作。当工人完成自己的工作后,调用latch.countDown()方法,按下计算器按钮,告诉生产线控制中心,表示我已经完成了按照轮子的任务。哈,我可以去喝口水了。

再看一下main函数中的latch.await()这行,表示,流水线一直在等待计数器被清零。当计算器为零后,可以统计这次装配用的整时间啦。

Java代码 收藏代码
public class Worker implements Runnable {
private int id;
private CountDownLatch latch;

public Worker(int id, CountDownLatch latch) {
this.id = id;
this.latch = latch;
}

@Override
public void run() {
try {
System.out.format("tyre %d is assembling.%n", id);
marshalTyre();
System.out.format("tyre %d is assembled.%n", id);
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}

}

private void marshalTyre() throws InterruptedException {
Thread.sleep(new Random().nextInt(60000));
}

/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(4);
ExecutorService executor = Executors.newFixedThreadPool(4);
long s = System.currentTimeMillis();
for (int i = 0; i < 4; i++)
executor.execute(new Worker(i, latch));
latch.await();
System.out.format("the 4 tyres were assembled. costs %d ms.%n", System.currentTimeMillis() - s);
executor.shutdown();
}
}

好了,我们对这个例子进行拓展,工人在装配轮胎之前,轮胎必须是已经放到了合适的位置,假如这辆车到达的时候,轮胎还没有准备好,那么必须等到轮胎准备就绪后才可以开始安装工作。换住话说,轮胎没有准备好,工人就一直处于等待“轮胎就绪”这个事件上。当轮胎准备好后,才可以安装。这种情况下,需要用到两把CountDownLatch。具体怎么用,下次再写。

[原创内容,版权所有,如有转载,请注明出处,如有错误之处,请指出,不胜感激]
---转自 http://mojarra.iteye.com/blog/1259288
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值