java并发闭锁和栅栏区别及使用

CountDownLatch和CyclicBarrier的主要联系和区别如下:
1.闭锁CountDownLatch做减计数,而栅栏CyclicBarrier则是加计数。
2.CountDownLatch是一次性的,CyclicBarrier可以重用。
3.CountDownLatch强调一个线程多个线程完成某件事情。CyclicBarrier是多个线程互等,等大家完成。
4.鉴于上面的描述,CyclicBarrier在一些场景中可以替代CountDownLatch实现类似的功能。
闭锁:
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
主要方法:

    1. CountDownLatch.await():将某个线程阻塞住,直到计数器count=0才恢复执行。 

    2. CountDownLatch.countDown():将计数器count减1。

应用场景

《1》确保某个计算在其需要的所有资源都被初始化之后才继续执行。二元闭锁(包括两个状态)可以用来表示“资源R已经被初始化”,而所有需要R的操作都必须先在这个闭锁上等待。
《2》确保某个服务在其依赖的所有其他服务都已经启动之后才启动。
《3》等待直到某个操作的所有参与者都就绪在继续执行。(例如:多人游戏中需要所有玩家准备才能开始)

栅栏则是一组线程相互等待,直到所有线程都到达某一点时才打开栅栏,然后线程可以继续执行,也就是说控制线程先设置一个时间点,然后这些线程各自执行,执行完等待(阻塞),直到这组线程中的所有线程执行完,然后控制线程栅栏打开,这些线程同时继续执行。栅栏强调的是各自执行完后的相互等待以及继续执行。
信号量根据一个计数器控制一个结果的数量,条件满足情况下才能进行增加和移除操作,否则进行操作的线程阻塞。
栅栏使用场景

 应用一些协议,比如几个家庭成员决定在某个地方集合,所有人在6:00在某地集合,到了以后要等待其他人,之后才能讨论去哪里吃饭。 并行迭代,将一个问题分成很多子问题,当一系列的子问题都解决之后(所有子问题线程都已经await()),此时将栅栏打开,所有子问题线程被释放,而栅栏位置可以留着下次使用。

CountDownLatch代码示例
《CountDownLatch》有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。所以在这里用Java代码设计两个类,Worker代表工人,Boss代表老板,具体的代码实现如下:

工人:

package LatchAndCyclicBarrier;
 
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
 
public class Work implements Runnable{
 
 
        private CountDownLatch downLatch;
        private String name;
 
        public Work(CountDownLatch downLatch, String name){
            this.downLatch = downLatch;
            this.name = name;
        }
 
        public void run() {
            this.doWork();
            try{
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            }catch(InterruptedException ie){
            }
            System.out.println(this.name + "活干完了!");
            this.downLatch.countDown();
 
        }
 
        private void doWork(){
            System.out.println(this.name + "正在干活!");
        }
 
    }
 

老板:

 
package LatchAndCyclicBarrier;
 
import java.util.concurrent.CountDownLatch;
 
public class Boss implements Runnable{
 
        private CountDownLatch downLatch;
 
        public Boss(CountDownLatch downLatch){
            this.downLatch = downLatch;
        }
 
        public void run() {
            System.out.println("老板正在等所有的工人干完活......");
            try {
                this.downLatch.await();
            } catch (InterruptedException e) {
            }
            System.out.println("工人活都干完了,老板开始检查了!");
        }
 
    }
 

测试

package LatchAndCyclicBarrier;
 
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
public class TestLatch {
 
    public static void main(String[] args) {
            ExecutorService executor = Executors.newCachedThreadPool();
 
            CountDownLatch latch = new CountDownLatch(3);
 
            Work w1 = new Work(latch,"张三");
            Work w2 = new Work(latch,"李四");
            Work w3 = new Work(latch,"王二");
 
            Boss boss = new Boss(latch);
 
            executor.execute(w3);
            executor.execute(w2);
            executor.execute(w1);
            executor.execute(boss);
 
            executor.shutdown();
        }
    }

结果:

李四正在干活!
老板正在等所有的工人干完活......
王二正在干活!
张三正在干活!
李四活干完了!
王二活干完了!
张三活干完了!
工人活都干完了,老板开始检查了!

CyclicBarrier代码示例
《CyclicBarrier》接着上面的例子,还是这三个工人,不过这一次,这三个工人自由了,老板不用检查他们任务了,他们三个合作建桥,有三个桩,每人打一个,同时打完之后才能一起搭桥(搭桥需要三人一起合作)。也就是说三个人都打完桩之后才能继续工作。

 
package LatchAndCyclicBarrier;
 
import java.util.concurrent.CyclicBarrier;
 
public class CycWork implements Runnable {
 
 
        private CyclicBarrier cyclicBarrier ;
        private String name ;
 
        public CycWork(CyclicBarrier cyclicBarrier,String name)
       {
               this .name =name;
               this .cyclicBarrier =cyclicBarrier;
       }
 
        @Override
        public void run() {
               // TODO Auto-generated method stub
 
              System. out .println(name +"正在打桩,毕竟不轻松。。。。。" );
 
               try {
                     Thread. sleep(5000);
                     System. out .println(name +"不容易,终于把桩打完了。。。。" );
                      cyclicBarrier .await();
 
              } catch (Exception e) {
                      // TODO: handle exception
                     e.printStackTrace();
              }
 
              System. out .println(name +":其他逗b把桩都打完了,又得忙活了。。。" );
 
 
       }
 
}

测试代码

package LatchAndCyclicBarrier;
 
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
public class CycTest {
 
        public static void main(String[] args)
       {
              ExecutorService executorpool=Executors. newFixedThreadPool(3);
              CyclicBarrier cyclicBarrier= new CyclicBarrier(3);
 
              CycWork work1= new CycWork(cyclicBarrier, "张三" );
              CycWork work2= new CycWork(cyclicBarrier, "李四" );
              CycWork work3= new CycWork(cyclicBarrier, "王五" );
 
              executorpool.execute(work1);
              executorpool.execute(work2);
              executorpool.execute(work3);
 
              executorpool.shutdown();
 
       }
 
}

结果


李四正在打桩,毕竟不轻松。。。。。
张三正在打桩,毕竟不轻松。。。。。
王五正在打桩,毕竟不轻松。。。。。
李四不容易,终于把桩打完了。。。。
张三不容易,终于把桩打完了。。。。
王五不容易,终于把桩打完了。。。。
王五:其他逗b把桩都打完了,又得忙活了。。。
李四:其他逗b把桩都打完了,又得忙活了。。。
张三:其他逗b把桩都打完了,又得忙活了。。。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值