JUC之CountDownLatchCyclicBarrierSemaphore

    技术2022-07-11  132

    目录

    CountDownLatch概念code演示结合枚举类 CyclicBarrier概念code演示, CountDownLatch和CyclicBarrierSemaphore概念code演示

    CountDownLatch

    概念

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

    code演示

    import java.util.concurrent.CountDownLatch; /** * 班里一共6个学生和班长,只有6个学生都走完班长才能锁门 */ public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { leaveClassroom(); } private static void leaveClassroom() throws InterruptedException { //给一个计数器,设置初始值为6 CountDownLatch countDownLatch=new CountDownLatch(6); for (int i = 1; i <=6 ; i++) { new Thread(()->{ System.out.println(Thread.currentThread().getName()+"上完自习,离开教室"); //计数器减一 countDownLatch.countDown(); },String.valueOf(i)).start(); } //让这个线程阻塞(在main线程里也就是让main线程阻塞) //一直到计数器为0时候会自动释放 countDownLatch.await(); System.out.println(Thread.currentThread().getName()+" ******班长最后关门走人"); } }

    结合枚举类

    import java.util.concurrent.CountDownLatch; public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { county(); } private static void county() throws InterruptedException { //给一个计数器,设置初始值为6 CountDownLatch countDownLatch=new CountDownLatch(6); for (int i = 1; i <=6 ; i++) { new Thread(()->{ System.out.println(Thread.currentThread().getName()+" 国被灭"); //计数器减一 countDownLatch.countDown(); }, CountryEnum.list(i).getRetMsg()).start(); } //让这个线程阻塞(在main线程里也就是让main线程阻塞) //一直到计数器为0时候会自动释放 countDownLatch.await(); System.out.println(Thread.currentThread().getName()+" ******秦国一统华夏"); } enum CountryEnum { ONE(1, "齐"), TWO(2, "楚"), THREE(3, "燕"), FOUR(4, "赵"), FIVE(5, "魏"), SIX(6, "韩"); private Integer retCode; private String retMsg; CountryEnum(Integer retCode, String retMsg) { this.retCode = retCode; this.retMsg = retMsg; } public Integer getRetCode() { return retCode; } public void setRetCode(Integer retCode) { this.retCode = retCode; } public String getRetMsg() { return retMsg; } public void setRetMsg(String retMsg) { this.retMsg = retMsg; } public static CountryEnum list(int idx) { CountryEnum[] countryEnums = CountryEnum.values(); for (CountryEnum countryEnum : countryEnums) { if (idx==countryEnum.getRetCode()) return countryEnum; } return null; } } }

    CyclicBarrier

    概念

    和CountDownLatch相比,他是加法操作,也是计数器,每个线程await()都会阻塞然后对计数器加1,一直加到设定的值其他线程才会执行

    字面意思是可循环使用的屏障。它要做的事情是,让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会打开,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await()方法

    code演示,

    import java.util.concurrent.CyclicBarrier; /** * 收集到7颗龙族才能召唤神龙 */ public class CyclicBarrierDemo { public static void main(String[] args) { //CyclicBarrier从0开始,一直加到7就会自动执行召唤神龙线程 CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> { System.out.println("*****召唤神龙"); }); for (int i = 1; i <= 7; i++) { final int tempInt = i; new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 收集到第" + tempInt + "颗龙珠"); try { //收集龙族的线程开始等待,一直到召唤完神龙才会唤醒 //CyclicBarrier调用await()让线程等待的同时,会对计数器加1 cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " over"); }, String.valueOf(i)).start(); } } } 2 收集到第2颗龙珠 1 收集到第1颗龙珠 4 收集到第4颗龙珠 3 收集到第3颗龙珠 6 收集到第6颗龙珠 5 收集到第5颗龙珠 7 收集到第7颗龙珠 *****召唤神龙 7 over 2 over 1 over 4 over 5 over 3 over 6 over

    CountDownLatch和CyclicBarrier

    最核心的不是++和–,其实这个效果差不多

    核心的是CountDownLatch参数不可以有线程 CyclicBarrier可以 new CyclicBarrier(5); new CyclicBarrier(5,()->{}); CyclicBarrier线程回阻塞,CountDownLatch只阻塞主线程

    Semaphore

    概念

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

    常用于秒杀等,多个线程抢夺多个资源场景

    CountDownLatch 减法,一只减到0CyclicBarrier 加法,加到指定值他们都是不能复用的

    code演示

    比如抢占车位,一个车开走了其他车是可以进来的

    比如CyclicBarrier 的count=3,那么加到3,就不能继续操作了。

    而Semaphore可以解决这个问题,比如6辆车3个停车位,对于CountDownLatch只能停3辆车,而Semaphore可以停6辆车,车位空出来后,其它车可以占有,这就涉及到了Semaphore.accquire()和Semaphore.release()方法

    import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; //抢车位 public class SemaphoreDemo { public static void main(String[] args) { //模拟3个停车位 Semaphore semaphore = new Semaphore(3); //模拟6个车 for (int i = 1; i <= 6; i++) { new Thread(() -> { try { semaphore.acquire(); System.out.println(Thread.currentThread().getName() + " 抢到车位"); //暂停一会线程模拟停车 try { TimeUnit.SECONDS.sleep(3); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 停车3秒后离开车位"); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } }, String.valueOf(i)).start(); } } } 1 抢到车位 2 抢到车位 3 抢到车位 1 停车3秒后离开车位 2 停车3秒后离开车位 3 停车3秒后离开车位 6 抢到车位 4 抢到车位 5 抢到车位 4 停车3秒后离开车位 6 停车3秒后离开车位 5 停车3秒后离开车位
    Processed: 0.013, SQL: 9