现实生活做中有很多这样的场景:做F前需要等待A,B,C,D,E完成,A,B,C,D,E可以并发完成,没有特定顺序,并且F做完后又重新开始,例如:组装汽车前需要先生产轮胎,车门,车身等等。这个场景的特征为:
1.组装汽车前有N件事情要做,每件事情都做完后才能组装汽车。
2.每件事情可以并行处理,没有先后顺序,因而提高了效率。
3.组装好一辆汽车后继续生产和组装下一辆。(当然现在所有零件都是批量生产,不是一个个来的,我们假设是人工造的限量版宾利,一量量来的。)
围绕造车,整个过程如下:
在应用程序中处理并行操作时也跟上述场景类似,碰到这种场景时可以通过java并发工具CyclicBarrier来实现。
代码类结构如下:
public class MakeCarBody implements Runnable { private CyclicBarrier cyclicBarrier; public MakeCarBody(CyclicBarrier cyclicBarrier) { this.cyclicBarrier = cyclicBarrier; } public void run() { exec(); } /** * 模拟模拟造车身 */ private void exec() { //造完后继续造下一个 while(true) { try { System.out.println("Start making car body..."); long millis = ((int) (1 + Math.random() * (5 - 1 + 1))) * 1000; TimeUnit.MILLISECONDS.sleep(millis); System.out.println("Making car body is finished."); //等待其他部件造完 this.cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } } 复制代码
public class MakeCarDoor implements Runnable { private CyclicBarrier cyclicBarrier; public MakeCarDoor(CyclicBarrier cyclicBarrier) { this.cyclicBarrier = cyclicBarrier; } public void run() { exec(); } /** * 模拟造车门 */ private void exec() { //造完后继续造下一个 while(true) { try { System.out.println("Start making car door..."); long millis = ((int) (1 + Math.random() * (5 - 1 + 1))) * 1000; TimeUnit.MILLISECONDS.sleep(millis); System.out.println("Making car door is finished."); //等待其他部件造完 this.cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } } 复制代码
public class MakeTire implements Runnable { private CyclicBarrier cyclicBarrier; public MakeTire(CyclicBarrier cyclicBarrier) { this.cyclicBarrier = cyclicBarrier; } public void run() { exec(); } /** * 模拟造轮胎 */ private void exec() { //造完后继续造下一个 while(true) { try { System.out.println("Start making tire..."); long millis = ((int) (1 + Math.random() * (5 - 1 + 1))) * 1000; TimeUnit.MILLISECONDS.sleep(millis); System.out.println("Making tire is finished."); //等待其他部件造完 this.cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } } 复制代码
public class AssembleCar implements Runnable { public void run() { try { System.out.println("Start assemble car..."); //模拟组装汽车 long millis = ((int)(1+Math.random()*(5-1+1))) * 1000; TimeUnit.MILLISECONDS.sleep(millis); System.out.println("Making assemble care is finished."); } catch (InterruptedException e) { e.printStackTrace(); } } } 复制代码
public class CyclicBarrierTest { public static void main(String[] args) { //有3个部件要造,造完后组装汽车 CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new AssembleCar()); Thread makeCarBody = new Thread(new MakeCarBody(cyclicBarrier)); Thread makeCarDoor = new Thread(new MakeCarDoor(cyclicBarrier)); Thread makeTire = new Thread(new MakeTire(cyclicBarrier)); makeCarBody.start(); makeCarDoor.start(); makeTire.start(); } } 复制代码
输出日志:
Start making car door... Start making tire... Start making car body... Making tire is finished. Making car door is finished. Making car body is finished. Start assemble car... Making assemble care is finished. Start making car body... Start making tire... Start making car door... Making car body is finished. Making tire is finished. Making car door is finished. Start assemble car... Making assemble care is finished. 复制代码
可以看到CyclicBarrier的使用方式如下:
1.CyclicBarrier的构造函数有2个参数,第1个参数是声明有几个部件需要制造(有几件事可以并行),第2个参数是一个Runnable,此参数代表并行完之后要做的最后一件事情。
2.每个部件造完后调用CyclicBarrier的await()方法等待启动下一轮。
3.当最后一个部件造完后则会自动调用CyclicBarrier构造函数中传入的Runnable的实现类。
4.Runnable实现类实现完成后重新开始下一轮。