juc学习六(CountDownLatchCyclicBarrier和Semaphore)

Posted mabaoying

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了juc学习六(CountDownLatchCyclicBarrier和Semaphore)相关的知识,希望对你有一定的参考价值。

CountDownLatch

 CountDownLatch闭锁是在java1.5被引入,存在于java.util.cucurrent包下。

CountDownLatch是一个同步辅助类,让一些线程阻塞直到另一些线程完成一系列操作后才被唤醒。CountDownLatch是通过一个计数器来实现的,计数器的初始值是线程的数量。

CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,调用线程会被阻塞。其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞),当计数器的值变为零时,表示所有线程都执行完毕,因调用await方法被阻塞的线程会被唤醒,继续执行。

当我们在完成某些运算时,只有其他所有线程运算全部完成,当前运算才继续执行,就需要使用CountDownLatch闭锁。

示例:

public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {
       //构造参数count为计数值
        CountDownLatch countDownLatch=new CountDownLatch(5);
        for(int i=1;i<=5;i++){
            new Thread(()-> {
                System.out.println(Thread.currentThread().getName() + "	 开始工作");
                //将count值减1
                countDownLatch.countDown();
            }).start();
        }
        //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
        countDownLatch.await();
        System.out.println(Thread.currentThread().getName()+"	 完成工作");
    }
}

CycliBarrier

CyclicBarrier字面意思就是可循环使用的屏障。就是让一组线程到达一个屏障(也叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await方法。

使用场景:可以用于多线程计算数据,最后合并计算结果的场景。

构造方法

    public CyclicBarrier(int parties)
    //parties 是参与线程的个数,Runnable 参数,这个参数的意思是最后一个到达线程要做的任务 
    public CyclicBarrier(int parties, Runnable barrierAction)

示例:

/**
 * 一个线程组的线程需要等待所有线程完成任务后再继续执行下一次任务
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier=new CyclicBarrier(7,()-> System.out.println("---------------全部完成"));
        for(int i=1;i<=7;i++){
            final int tmpI=i;
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"	执行线程:"+tmpI+"成功");
                try {
                    //线程调用 await() 表示自己已经到达栅栏
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //BrokenBarrierException 表示栅栏已经被破坏,破坏的原因可能是其中一个线程 await() 时被中断或者超时
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}
 
CountDownLatch和CyclicBarrier区别:
1.countDownLatch是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次
2.CyclicBarrier的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,提供reset功能,可以多次使用

Semaphore 

Semaphore 是一个计数信号量,主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程的控制。

用途
单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。
多个信号量的Semaphore对象可以实现用于并发线程的控制。

示例:

/**
 * 5个线程抢占2个资源,只允许两个线程同时访问
 */
public class SemaphoreDemo {

    public static void main(String[] args) {
        //信号量,只允许2个线程同时访问,其他线程只能等待
        Semaphore semaphore=new Semaphore(2);
        for(int i=1;i<=5;i++){
            new Thread(()->{
                try {
                    //从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"	抢到资源");
                    //暂停三秒
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(Thread.currentThread().getName()+"	3秒后释放资源");
                    //释放一个许可,将其返回给信号量
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

  

  

  

 

以上是关于juc学习六(CountDownLatchCyclicBarrier和Semaphore)的主要内容,如果未能解决你的问题,请参考以下文章

JUC—Executor线程池框架源码深度解析六万字

JUC并发包UML全量类图

JUC并发包UML全量类图

并发编程的基石——AQS类

JUC - 共享模型之工具 - 第六篇

尚硅谷JUC高并发编程学习笔记JUC简介与Lock接口