java并发之CyclicBarrier
一、CyclicBarrier简述
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环的barrier。
CyclicBarrier支持一个可选的Runnable
命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作很有用。
二、使用场景代码示例
假设我们需要测试某台服务器能改有承受的并发访问量
1 public class CyclicBarrierTest { 2 3 public static void main(String[] args) { 4 int threadNum = 3; 5 ExecutorService executor = Executors.newFixedThreadPool(threadNum); 6 CyclicBarrier barrier = new CyclicBarrier(threadNum); 7 for (int i = 0; i < threadNum; i++) { 8 executor.submit(new Thread(new Runn(barrier))); 9 } 10 executor.shutdown(); 11 while (true) { 12 System.out.println(Thread.currentThread().getName()+" 当前在屏障处等待的参与者数目:"+barrier.getNumberWaiting()); 13 try { 14 Thread.sleep(1000); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 } 18 } 19 } 20 } 21 22 class Runn implements Runnable{ 23 24 private CyclicBarrier cyclicBarrier; 25 26 public Runn(CyclicBarrier cyclicBarrier) { 27 super(); 28 this.cyclicBarrier = cyclicBarrier; 29 } 30 31 @Override 32 public void run() { 33 try { 34 int m = 1000 * (new Random()).nextInt(8); 35 Thread.sleep(m);// 模拟准备业务耗时 36 System.out.println(Thread.currentThread().getName() + " 准备好了,准备耗时:"+m+"毫秒"); 37 // barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。 38 cyclicBarrier.await(); 39 } catch (InterruptedException e) { 40 e.printStackTrace(); 41 } catch (BrokenBarrierException e) { 42 e.printStackTrace(); 43 } 44 System.out.println(Thread.currentThread().getName() + " 开始处理核心业务,当前时间"+System.currentTimeMillis()); 45 } 46 47 }
main 当前在屏障处等待的参与者数目:0 main 当前在屏障处等待的参与者数目:0 pool-1-thread-1 准备好了,准备耗时:2000毫秒 main 当前在屏障处等待的参与者数目:1 main 当前在屏障处等待的参与者数目:1 main 当前在屏障处等待的参与者数目:1 pool-1-thread-2 准备好了,准备耗时:5000毫秒 main 当前在屏障处等待的参与者数目:2 main 当前在屏障处等待的参与者数目:2 pool-1-thread-3 准备好了,准备耗时:7000毫秒 pool-1-thread-1 开始处理核心业务,当前时间1492222079775 pool-1-thread-2 开始处理核心业务,当前时间1492222079775 pool-1-thread-3 开始处理核心业务,当前时间1492222079775 main 当前在屏障处等待的参与者数目:0