【Java面试高频-锁体系】- CyclicBarrier是什么?

【摘要】 【Java面试高频-锁体系】- CyclicBarrier是什么?
从字面上的意思可以知道,这个类的中文意思是“循环栅栏”。大概的意思就是一个可循环利用的屏障;
它的作用就是会让所有线程都等待完成后才会继续下一步行动。
举个例子:就像生活中我们会约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是这个餐厅规定必须等到所有人到齐之后才会让我们进去…

【Java面试高频-锁体系】- CyclicBarrier是什么?

从字面上的意思可以知道,这个类的中文意思是“循环栅栏”。大概的意思就是一个可循环利用的屏障;

它的作用就是会让所有线程都等待完成后才会继续下一步行动。

举个例子:就像生活中我们会约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是这个餐厅规定必须等到所有人到齐之后才会让我们进去。这里的朋友们就是各个线程,餐厅就是 CyclicBarrier。

1 CountDownLatch与CyclicBarrier的使用场景与区别对比

CountDownLatch的使用场景:

在一些应用场合中,需要等待某个条件达到要求后才能做后面的事情;同时当线程都完成后也会触发事件,以便进行后面的操作,这个时候就可以使用CountDownLatch。 CountDownLatch最重要的方法是countDown()和await(),前者主要是倒数一次,后者是等待倒数到0,如果没有到达0,就只有阻塞等待了;

CyclicBarrier的使用场景:

CyclicBarrier可以用于多线程计算数据,最后合并计算结果的应用场景。比如我们用一个Excel保存了用户所有有很那个流水,每个Sheet保存一个账户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个sheet里面的银行流水,都执行完成之后,得到每个sheet中的日均银行流水。最后,再用barrierAcition用这些线程的计算结果,计算出整个Excel的日均银行流水。

cyclicBarrier和CountDownLatch的区别是什么

  • a. CountDownLatch简单的说就是一个线程等待,直到它所等待的其他线程都执行完成并且调用countDown()方法发出通知后,当前线程才可以继续执行。
  • b. cyclicBarrier是所有线程都进行等待,直到所有线程都准备好进入await()方法之后,所有线程同时开始执行!
  • c.CountDownLatch的计数器只能使用一次,而cyclicBarrier的计数器可以使用reset()方法重置。所以CyclicBarrier能够处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程重新执行一次;

2 CountDownLatch与CyclicBarrier的例子

CountDownLatch的例子

public class CountDownLatchTest {
	public static void main(String[] args) {
		// 实例化一个countDownLatch对象
		final CountDownLatch countDownLatch = new CountDownLatch(2);
		// 创建一个线程1
		new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { System.out.println("进入线程t1 等待其它线程处理完成..."); countDownLatch.await(); System.out.println("t1线程继续执行..."); }catch(InterruptedException e) { e.printStackTrace(); } }
		},"t1").start(); //创建一个线程t2
		new Thread(new Runnable() { @Override public void run() { try { System.out.println("进入线程t2进行初始化操作……"); Thread.sleep(2000); System.out.println("t2线程执行完毕。。。"); countDownLatch.countDown(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
		},"t2").start();
		//创建一个线程t3
		new Thread(new Runnable() { @Override public void run() { try { System.out.println("进入线程t3进行初始化操作……"); Thread.sleep(4000); System.out.println("t3线程执行完毕。。。"); countDownLatch.countDown(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
		},"t3").start();
	}
}
  
 

执行结果如下:

进入线程t1 等待其他线程处理完成……
进入线程t3进行初始化操作……
进入线程t2进行初始化操作……
t3线程执行完毕。。。
t2线程执行完毕。。。
t1线程继续执行……

分析CountDownLatch:
运行程序我们会发现当我们在t1调用CountDownLatch的await()方法时,就好比我们调用了wait()方法,当前线程会处于阻塞状态,直到等到t2和t3完全执行完毕并且调用countDown()方法时,我们才能唤醒t1继续进行执行,CountDownLatch就好比一个计时器,我们可以让当前线程调用CountDownLatch中的await()方法进行等待,如果想让当前线程继续执行,我们必须让CountDownLatch获得初始化时候传入的构造参数个countDown()方法,我们才能继续执行。

CyclicBarrier

package com.lcz.thread;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Runner implements Runnable{
	private String name;
	private CyclicBarrier cyclicBarrier; public Runner(CyclicBarrier cyclicBarrier,String name) {
		this.name = name;
		this.cyclicBarrier = cyclicBarrier;
	} @Override
	public void run() {
		// TODO Auto-generated method stub
		try { Thread.sleep(1000*new Random().nextInt(5)); System.out.println(Thread.currentThread().getName()+"已准备好"); cyclicBarrier.await();
		}catch (InterruptedException e) { // TODO: handle exception e.printStackTrace();
		}catch(BrokenBarrierException e) { e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"出发!");
	}
	
}

public class CyclicBarrierTest {
	public static void main(String[] args) {
		CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		try { executorService.execute(new Runner(cyclicBarrier, "张三")); executorService.execute(new Runner(cyclicBarrier, "李四")); executorService.execute(new Runner(cyclicBarrier, "王五"));
		} finally { executorService.shutdown();
		}
	}
}
  
 

执行结果如下:
pool-1-thread-1已经准备好
pool-1-thread-3已经准备好
pool-1-thread-2已经准备好
pool-1-thread-2出发!!
pool-1-thread-1出发!!
pool-1-thread-3出发!!

CyclicBarrier 分析结果:
上述程序我们创建了一个线程池,这个线程池中有三个线程,每个线程都传递了一个相同的 CyclicBarrier 对象和运动员的名字,我们Runner类中的run方法使每一个进来的运动员都休眠0-5秒的时间,然后调用await()方法,就是说每个线程进来都需要进行等待,直到所有的CyclicBarrier 都处于准备好了的状态,所有线程才能统一开始执行!

文章来源: blog.csdn.net,作者:mind_programmonkey,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/Mind_programmonkey/article/details/116740214

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享