CountDownLatch 多线程同步辅助类
CountDownLatch latch = new CountDownLatch (1); 是给定计数为1,当运行CountDownLatch 类的线程判断计数不为0的时候则呈现等待状态,如果为0则继续运行。计数器无法被重置,计数操作是做的减法。await()实现等待,countDown()继续执行。`
运动员比赛测试代码
import java.util.concurrent.CountDownLatch;
public class MyThread1 extends Thread {
private CountDownLatch comintTag;
private CountDownLatch waitTag;
private CountDownLatch endTag;
public MyThread1(CountDownLatch comintTag, CountDownLatch waitTag, CountDownLatch endTag) {
super();
this.comintTag = comintTag;
this.waitTag = waitTag;
this.endTag = endTag;
}
@Override
public void run() {
try {
String threadName = Thread.currentThread().getName() + "--";
System.out.println(threadName + "运动员正赶往起跑点");
Thread.sleep((int) Math.random() * 1000);
System.out.println(threadName + "跑到起点");
comintTag.countDown();
System.out.println(threadName + "等待起跑指令");
waitTag.await();
System.out.println(threadName + "跑出起点");
Thread.sleep((int) Math.random() * 1000);
System.out.println(threadName + "跑到终点");
endTag.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
CountDownLatch comintTag = new CountDownLatch(4);
CountDownLatch waitTag = new CountDownLatch(1);
CountDownLatch endTag = new CountDownLatch(4);
MyThread1[] thread1s = new MyThread1[4];
Arrays.stream(thread1s).forEach(m->{
m=new MyThread1(comintTag, waitTag, endTag);
m.start();
});
System.out.println("裁判等待运动员到来");
try {
comintTag.await();
System.out.println("运动员到来完毕,发出起跑命令");
waitTag.countDown();
System.out.println("等待跑完统计名次");
endTag.await();
System.out.println("裁判统计名次");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
运行结果
Thread-1–运动员正赶往起跑点
裁判等待运动员到来
Thread-0–运动员正赶往起跑点
Thread-2–运动员正赶往起跑点
Thread-3–运动员正赶往起跑点
Thread-2–跑到起点
Thread-1–跑到起点
Thread-1–等待起跑指令
Thread-3–跑到起点
Thread-3–等待起跑指令
Thread-0–跑到起点
Thread-0–等待起跑指令
Thread-2–等待起跑指令
运动员到来完毕,发出起跑命令
等待跑完统计名次
Thread-1–跑出起点
Thread-3–跑出起点
Thread-0–跑出起点
Thread-2–跑出起点
Thread-1–跑到终点
Thread-0–跑到终点
Thread-3–跑到终点
Thread-2–跑到终点
裁判统计名次
CountDownLatch 部分方法
boolean await(long timeout, TimeUnit unit); 作用是在指定时间内进行等待状态,超过时间则自动唤醒往下运行。
long getCount() ;获取当前计数的值。
CyclicBarrier
CyclicBarrier不仅具有CountDownLatch 的所有功能,还可以实现屏障等待的功能,就是阶段性同步,可以循环的实现线程要一起做任务的目标,而不像CountDownLatch 只支持一次的特点。
CountDownLatch 作用:一个线程或者多个线程等待另外一个线程或者多个线程完成某个事件。
CyclicBarrier 作用:多个线程之间相互等待,任何一个线程完成之前,所有的线程都必须等待,所以对于CyclicBarrier 来说重点是"多个线程之间"任何一个线程没有完成任务,则所有线程都必须等待。
CyclicBarrier的分批次处理
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class MyThreadCyc extends Thread{
private CyclicBarrier cyc;
public MyThreadCyc(CyclicBarrier cyc) {
this.cyc = cyc;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+" 等待筹齐2个线程再继续运行");
cyc.await();
System.out.println(Thread.currentThread().getName()+" 已经筹齐2个线程开始继续运行");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
CyclicBarrier cyc = new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
System.out.println("都到了");
}
});
for (int i = 0; i < 4; i++) {
Thread a = new MyThreadCyc(cyc);
a.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试结果
Thread-0 等待筹齐2个线程再继续运行
Thread-1 等待筹齐2个线程再继续运行
都到了
Thread-1 已经筹齐2个线程开始继续运行
Thread-0 已经筹齐2个线程开始继续运行
Thread-2 等待筹齐2个线程再继续运行
Thread-3 等待筹齐2个线程再继续运行
都到了
Thread-3 已经筹齐2个线程开始继续运行
Thread-2 已经筹齐2个线程开始继续运行
CyclicBarrier 实现分阶段跑步比赛
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class MyThreadCyc2 extends Thread{
private CyclicBarrier cyc;
public MyThreadCyc2(CyclicBarrier cyc) {
this.cyc = cyc;
}
@Override
public void run() {
try {
Thread.sleep((int) Math.random()*1000);
String threadName = Thread.currentThread().getName()+"--";
System.out.println(threadName+" 开始跑第一阶段");
cyc.await();
System.out.println(threadName+" 跑完第一阶段");
Thread.sleep((int) Math.random()*1000);
System.out.println(threadName+" 开始跑第二阶段");
cyc.await();
System.out.println(threadName+" 跑完第二阶段");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
CyclicBarrier cyc = new CyclicBarrier(2);
for (int i = 0; i < 4; i++) {
Thread a = new MyThreadCyc2(cyc);
a.setName("线程"+i);
a.start();
}
}
测试结果
线程3-- 开始跑第一阶段
线程0-- 开始跑第一阶段
线程2-- 开始跑第一阶段
线程1-- 开始跑第一阶段
线程1-- 跑完第一阶段
线程1-- 开始跑第二阶段
线程0-- 跑完第一阶段
线程2-- 跑完第一阶段
线程0-- 开始跑第二阶段
线程3-- 跑完第一阶段
线程0-- 跑完第二阶段
线程1-- 跑完第二阶段
线程3-- 开始跑第二阶段
线程2-- 开始跑第二阶段
线程2-- 跑完第二阶段
线程3-- 跑完第二阶段
CyclicBarrier 方法
int getNumberWaiting();获得有几个线程已经到达屏障点。
boolean isBroken(); 查询屏障点是否损坏。
int await(long timeout, TimeUnit unit);在指定时间内到达屏障点指定数量则继续运行,否则抛出TimeoutException;
int getParties();取得屏障点设置的个数。
void reset();重置屏障;
CyclicBarrier 对于线程中断的InterruptedException会使用全有或者全无的的破坏模型,如果有一个线程由于你中断或者超时提前离开屏障点,其余在屏障点等待的线程都会抛出BrokenBarrierException或者InterruptedException并且离开屏障点。