功能
它可以让一组线程全部达到一个状态之后全部同时执行。
回环屏障
回环:所有等待的线程执行完毕,重置CyclicBarrier状态后它可以被重用。
屏障:线程调用await方法后会被阻塞,这个阻塞点称为屏障点,所有子线程都调用了await方法之后,子线程就会冲破屏障点,继续运行。
案例
package concurrentProgramming;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierTest1 {
//创建一个CyclicBarrier实例线程,当所有的子线程都达到一个屏障之后会运行该线程
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread()+"子线程已经达到屏障点!");
}
});
public static void main(String[] args) {
//创建一个线程个数固定为2的线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);
//创建第一个子线程1
executorService.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread()+"子线程1");
System.out.println(Thread.currentThread()+"子线程1进入barrier!");
//子线程1的屏障点
cyclicBarrier.await();
System.out.println(Thread.currentThread()+"子线程1结束Barrier!");
} catch (Exception e) {
e.printStackTrace();
}
}
});
//创建第一个子线程2
executorService.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread()+"子线程2");
System.out.println(Thread.currentThread()+"子线程2进入barrier!");
//子线程2的屏障点
cyclicBarrier.await();
System.out.println(Thread.currentThread()+"子线程2结束Barrier!");
} catch (Exception e) {
e.printStackTrace();
}
}
});
//关闭线程池
executorService.shutdown();
}
}
运行结果:
Thread[pool-1-thread-1,5,main]子线程1
Thread[pool-1-thread-2,5,main]子线程2
Thread[pool-1-thread-2,5,main]子线程2进入barrier!
Thread[pool-1-thread-1,5,main]子线程1进入barrier!
Thread[pool-1-thread-1,5,main]子线程已经达到屏障点!
Thread[pool-1-thread-1,5,main]子线程1结束Barrier!
Thread[pool-1-thread-2,5,main]子线程2结束Barrier!
由上述案例可以得知当所有的子线程都调用await方法之后就已经到达屏障点,此时会运行CyclicBarrier实例化时构造函数传入的线程。
案例2
假设有如下要求
- 每个任务有三个阶段,阶段1,阶段2,阶段3。
- 每个线程要串行的执行阶段1,阶段2,阶段2。
- 多个线程同时执行该任务时,只有每个任务的阶段1都执行完之后,才能执行阶段2,每个任务的阶段2全部执行完之后才能执行阶段3。
代码实现:
package concurrentProgramming;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierTest2 {
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
//创建线程1
executorService.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread()+"step1");
cyclicBarrier.await();
System.out.println(Thread.currentThread()+"step2");
cyclicBarrier.await();
System.out.println(Thread.currentThread()+"step3");
} catch (Exception e) {
e.printStackTrace();
}
}
});
//创建线程2
executorService.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread()+"step1");
cyclicBarrier.await();
System.out.println(Thread.currentThread()+"step2");
cyclicBarrier.await();
System.out.println(Thread.currentThread()+"step3");
} catch (Exception e) {
e.printStackTrace();
}
}
});
executorService.shutdown();
}
}
运行结果:
Thread[pool-1-thread-1,5,main]step1
Thread[pool-1-thread-2,5,main]step1
Thread[pool-1-thread-1,5,main]step2
Thread[pool-1-thread-2,5,main]step2
Thread[pool-1-thread-1,5,main]step3
Thread[pool-1-thread-2,5,main]step3
Process finished with exit code 0
原理探究
构造函数
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
public CyclicBarrier(int parties) {
this(parties, null);
}
成员变量:
/** The lock for guarding barrier entry */
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
private final Condition trip = lock.newCondition();
/** The number of parties */
private final int parties;
/* The command to run when tripped */
private final Runnable barrierCommand;
/** The current generation */
private Generation generation = new Generation();
CyclicBarrier也是基于独占锁实现的,本质底层还是基于AQS的。
parties用来记录线程数,这里表示多少线程调用await之后,所有线程才会冲破屏障继续往下运行。
trip 独占锁的条件变量,通过条队列来实现线程同步。
主要方法
int await()
当线程调用该方法是就会被阻塞,直到满足一下条件就会返回:
- parties个线程调用了await方法,线程达到屏障点
- 其他线程中断当前线程,抛出异常
- 关联的Generation 对象的broken标志被置为true时,抛出异常。
boolean await(long timeOut , TimeUnit unit)
和上一个方法类似,但是返回值发生变化,并且超时之后会返回false。