【第六章】JUC之常见辅助类CountDownLatch、CyclicBarrier、Semaphore应用详解

一、CountDownLatch减少计数

await():是当前线程等待直到锁向下计数为0,除非线程interrupted;

countDown():减少锁的数量,释放所有等待的线程。

基本原理

  CountDownLatch主要有两个方法,当线程调用await()时,此时线程会被阻塞;当线程调用countDown()会将计数器减1(调用CountDown()的线程不会阻塞)。

  当计数器值变为0时,await()阻塞的线程就会被唤醒,继续执行!

在这里插入图片描述

测试代码1-1
//期望输出:非主线程执行完毕后再执行主线程
public class CountDownLatchDemo {
    public static void main(String[] args) {
        for (int i = 1; i <=6; i++) {
            new Thread(() ->{
                System.out.println(Thread.currentThread().getName()+"\t号员工已下班打卡");
            },String.valueOf(i)).start();
        }
        //主线程
        System.out.println(Thread.currentThread().getName()+"\t锁门");
    }
}
打印结果

不符合要求!明显1-6号员工的线程没有执行完毕,主程序就提前执行了!

在这里插入图片描述

测试代码1-2
//枚举类
public enum EmployeeEnum {
    ONE(1, "林大侠"),
    TWO(2, "周大侠"),
    THREE(3, "李大侠"),
    FOUR(4, "猪大侠"),
    FIVE(5, "乔大侠"),
    SIX(6, "刘大侠");
    private int code;
    private String empName;
    EmployeeEnum(int code, String empName) {
        this.code = code;
        this.empName = empName;
    }
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    public static EmployeeEnum foreach_EmployeeEnum(int index) {
        EmployeeEnum[] employee = EmployeeEnum.values();
        for (EmployeeEnum employeeEnum : employee) {
            if (employeeEnum.getCode() == index) {
                return employeeEnum;
            }
        }
        return null;
    }
}
import com.lindaxia.gmall.jucdemo.jucdemo.enums.EmployeeEnum;
import java.util.concurrent.CountDownLatch;
/**
 * 减少计数
 */
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        //初始化,指定计数器
        CountDownLatch cd = new CountDownLatch(6);
        for (int i = 1; i <=6; i++) {
            new Thread(() ->{
                System.out.println(Thread.currentThread().getName()+"\t员工已下班打卡");
               cd.countDown(); //计数器减1,其它线程不阻塞
            }, EmployeeEnum.foreach_EmployeeEnum(i).getEmpName()).start();

        }
        cd.await();当前线程等待直到锁向下计数为0,才会被唤醒(放行)
        //主线程
        System.out.println(Thread.currentThread().getName()+"\t保安锁门");
    }
}
打印结果:

符合期望输出!

在这里插入图片描述

二、CyclicBarrier循环栅栏(加)
基本原理

  CyclicBarrier顾名思义可循环(Cyclic)使用的屏障(Barrier。具体的功能如下:

  让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。线程进入屏障通过CyclicBarrierawait()方法。

测试代码
import java.util.concurrent.CyclicBarrier;
/**
 * 循环屏障
 *
 * 集齐7颗龙珠召唤神龙、集五福
 */
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("集齐7颗龙珠召唤神龙!");
        });
        for (int i = 1; i <=7 ; i++) {
            new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName()+"\t星龙珠被收集");
                    cyclicBarrier.await(); //阻塞线程
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}
打印结果

在这里插入图片描述

三、Semaphore信息灯
基本原理

  在信号量上可定义两种操作:

  acquire(获取/抢占) 当一个线程调用acquire操作时,它要么通过成功获取信号量(信号量减1),要么一直等下去,直到有线程释放信号量,或超时。

  release(释放)实际上会将信号量的值加1,然后唤醒等待的线程。

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

测试代码

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SemaphoreDemo {
    public static void main(String[] args) {
        //3个停车位
        Semaphore sp = new Semaphore(3);
        //6俩轿车
        for (int i = 1; i <=6 ; i++) {
            new Thread(()->{
                try {
                    sp.acquire();//抢占车位
                    System.out.println(Thread.currentThread().getName()+"\t号车驶入停车位!!!");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(Thread.currentThread().getName()+"\t号车离开停车位!!!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    sp.release();//无论抢占是否成功,都要腾车位(释放资源)
                }
            },String.valueOf(i)).start();
        }
    }
}
打印结果

在这里插入图片描述


 ☝上述分享来源个人总结,如果分享对您有帮忙,希望您积极转载;如果您有不同的见解,希望您积极留言,让我们一起探讨,您的鼓励将是我前进道路上一份助力,非常感谢!我会不定时更新相关技术动态,同时我也会不断完善自己,提升技术,希望与君同成长同进步!

☞本人博客:https://coding0110lin.blog.csdn.net/  欢迎转载,一起技术交流吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值