阅读 152

CountDownLatch和CyclicBarrier控制线程间的步调一致

CountDownLatch和CyclicBarrier控制线程间的步调一致

CountDownLatch ‘线程间可见的计数器’

CountDownLatch latch = new CountDownLatch(num);// num=需要控制的线程数
latch.countDown();// 计数器减一 num--;
latch.await();// 等待计数器为0,num==0,然后继续执行下面的代码
复制代码

不支持循环使用CountDownLatch,每次使用必须重新初始化计数器;

CyclicBarrier ‘线程间可见、自动重置的计数器’

CyclicBarrier barrier = new CyclicBarrier(num, barrierAction);
// num=需要控制的线程数; barrierAction=计数器为0后执行的任务
barrier.await();
// 执行计数器-1,减完后如果计数器为0,则当前线程去执行barrierAction,否则阻塞线程;
复制代码

执行完barrierAction后计数器会自动重置不用重新初始化

借助CountDownLatch和CyclicBarrier优化串行程序

Executor executor = Executors.newFixedThreadPool(2);
// 计数器初始化为 2
CountDownLatch latch = new CountDownLatch(2);
// 查询数据A
executor.execute(()-> {
 data_a =selectDb(a);
 latch.countDown();
 });
 // 查询数据B
 executor.execute(()-> {
 data_b =selectEs(b);
 latch.countDown();
 });
 // 等待两个查询操作结束
 latch.await();
 // 执行后续操作
 res = mixData(data_a, data_b);
 save(res)
复制代码

线程的执行图

image-20210704211755953

查询数据和后续操作任然是串行的,实际上也可做到并行,在执行后续操作的时候进行下次数据的组装;反映在坐标图中则为:

image-20210704212254847

//订单队列
Vector<Data> data_a;
// 派送单队列
Vector<Data> data_b;
// 执行回调的线程池
Executor executor = Executors.newFixedThreadPool(1);
final CyclicBarrier barrier = new CyclicBarrier(2, ()->{
 	executor.execute(()->check());
 });

 void check(){
	 Data a = data_a.remove(0);
	 Data b = data_b.remove(0);
	 res = check(a, b);
	 save(res);
 }

void checkAll(){
  
 Thread T1 = new Thread(()->{
   while(存在数据a){
     pos.add(selectDb());
     // 等待
     barrier.await();
   }
 });
 T1.start(); 

 Thread T2 = new Thread(()->{
   while(存在数据b){
     dos.add(selectEs());
     // 等待
     barrier.await();
   }
 });
 T2.start();
}
复制代码

文章分类
后端
文章标签