Java分布式应用学习笔记05多线程下的并发同步器----后篇
5. CountDownLatch
很多资料上都说CountDownLatch是倒数计数器,我觉得这种说法太过专业,其实它就是一个数数的人员。利用它,可以在多线程执行任务完毕后完成进行多线程的等待,便于等待所有的线程之后在干别的事情,这个有点类似于FutureTask,使用上不太一样。这个场景就是一个线程必须要等到其他线程执行完毕后才能往下执行,注意,这里这个线程没必要需要其他线程的执行结果,而是只有一个条件就是其他线程必须执行完毕。咱们依然做个比喻,韦小宝需要8部《四十二章经》才能去鹿鼎山找寻宝藏,怎么办,他有7个老婆,不能资源浪费啊,这个任务同时进行吧。咱们设计8个线程同时进行,等所有老婆都执行完毕了,每个老婆找齐了《四十二章经》了,好了,他可以自己去找宝藏了。等等,咱们小宝哥有7个老婆,何来8个线程,这个问题,读者不必较真,举个例子罢了,咱们给他加个老婆不就行了!
代码如下
Java代码
<span style="font-size: small;">package threadConcurrent.test;
import java.util.concurrent.CountDownLatch;
/**
* 分部执行任务
*
* @author liuyan
*
*/
public class CountDownLatchDemo implements Runnable {
private int id;
// 线程之间不影响,到了终点后继续做自己的事情
private CountDownLatch countDownLatch;
public CountDownLatchDemo(int id, CountDownLatch countDownLatch) {
this.id = id;
this.countDownLatch = countDownLatch;
}
@SuppressWarnings("static-access")
@Override
public void run() {
try {
System.out.println("第" + (id + 1) + "小老婆开始查找《四十二章经》...");
Thread.currentThread().sleep(id * 1000);
System.out.println("第" + (id + 1) + "本《四十二章经》找到");
//计数器将等待数字-1
countDownLatch.countDown();
System.out.println("第" + (id + 1) + "小老婆继续干其他事情");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(8);
for (int i = 0; i < 8; i++) {
new Thread(new CountDownLatchDemo(i, countDownLatch)).start();
}
try {
System.out.println("韦小宝等着等着8本四十二章……");
// 韦小宝等着等着
countDownLatch.await();
// 等待运动员到达终点
System.out.println("8本四十二章经找寻完成,可以寻宝了!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}</span>
主线程就当做是韦小宝吧,主线程首先开辟了线程计数器对象,之后就开辟了8个线程,派出了8个小老婆去办事,之后主线程调用countDownLatch.await()阻塞,在家里一直喝着小茶,听着小曲等着8个线程的执行完毕。咱们来看小老婆们,小老婆们就辛苦了,开始找寻经书,之后调用countDownLatch.countDown()方法通知线程计数器减去1,让等待的线程减去1。就好比说有个小老婆找到了《四十二章经》,用iphone发个彩信将经书的夹缝地图发给韦小宝,韦小宝收到了,恩,这个老婆能干,任务完成,我的等待目标减去1。等到等待线程为0的时候,小宝开始行动了,将手机里的地图通过游戏——拼图游戏,一拼凑,大事可成,自己寻宝去!这里大家也看到了CountDownLatch与FutureTask的区别。CountDownLatch侧重的是分线程的完成个数,每次完成一个分线程,等待数目减少一个,等待线程为0的时候,主线程的就不阻塞了,开始往下走。而分线程一旦调用countDownLatch.countDown()方法,就代表分线程任务搞定,主线程就不会因为你的其他事情而不能往下走,完成任务了,小老婆们也可以去旅旅游,休息休息!而FutureTask则是注重执行结果的,主线程需要它的确切结果。所以futureTask执行的call()有返回值。
6. CyclicBarrier
CyclicBarrier相对于CountDownLatch来说,最大的不同是,分线程具体的执行过程受其他分线程的影响,必须每个分线程都执行完毕了,主线程才继续往下走,而分线程如果在所有分线程执行完毕后还有其他动作,ok,还你自由,不必阻塞了,往下走你的路吧。这个例子是网上的游戏玩家的例子,4个小孩玩游戏,游戏要求必须是4个小孩都得通过第一关,才能开启第二关的关口!否则其他完成第一关的人都得等着其他人完成。这个有点像我们的项目开发,分模块开发,到一定阶段将模块汇总,联调,测试,如果这时候有一个模块没完成,大家等着吧,大家都在那里静静地、盯着你、等着你。
Java代码
<span style="font-size: small;">package threadConcurrent.test;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class GameBarrier {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {
@Override
public void run() {
System.out.println("所有玩家进入第二关!");
}
});
for (int i = 0; i < 4; i++) {
new Thread(new Player(i, cyclicBarrier)).start();
}
}
}
class Player implements Runnable {
/**
* 线程之间需要交互,到一
补充:软件开发 , Java ,