06_CountDownLatch/CyclicBarrier/Semaphore

1. CountDownLatch

概念

让一些线程阻塞直到另一些线程完成一系列操作才被唤醒

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

场景

现在有这样一个场景,假设一个自习室里有7个人,其中有一个是班长,班长的主要职责就是在其它6个同学走了后,关灯,锁教室门,然后走人,因此班长是需要最后一个走的,那么有什么方法能够控制班长这个线程是最后一个执行,而其它线程是随机执行的

解决方案

这个时候就用到了CountDownLatch,计数器了。我们一共创建6个线程,然后计数器的值也设置成6

// 计数器
CountDownLatch countDownLatch = new CountDownLatch(6)

然后每次学生线程执行完,就让计数器的值减1

for (int i = 0; i <= 6; i++) {
    new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + "\t 上完自习,离开教室");
        countDownLatch.countDown();
    }, String.valueOf(i)).start();
}

最后我们需要通过CountDownLatch的await方法来控制班长主线程的执行,这里 countDownLatch.await()可以想成是一道墙,只有当计数器的值为0的时候,墙才会消失,主线程才能继续往下执行

countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "\t 班长最后关门");

不加CountDownLatch的执行结果,我们发现main线程提前已经执行完成了,把一部分人锁屋里了
,在这里插入图片描述

引入CountDownLatch后的执行结果,我们能够控制住main方法的执行,这样能够保证前提任务的执行

在这里插入图片描述
完整代码

public class CountDownLatchDemo1 {

    public static void main(String[] args) throws InterruptedException {
        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();
        }

        countDownLatch.await();
        System.out.println("班长最后走锁门...............");
    }

}

和枚举类型联合使用

package com.wfg.mylock;

import jdk.nashorn.internal.objects.annotations.Getter;

/**
 * javaee
 *
 * @Title: com.wfg.mylock
 * @Date: 2020/9/26 11:37
 * @Author: wfg
 * @Description:
 * @Version:
 */
public enum CountDownLatchEnum {

    ONE(1,"齐"),TWO(2,"楚"),THREE(3,"燕"),FORE(4,"赵"),FIVE(5,"魏"),SIX(6,"韩");

    CountDownLatchEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    private int code;

    private String msg;

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public static CountDownLatchEnum foreachEnum(int index){
        CountDownLatchEnum[] countDownLatchEnums = CountDownLatchEnum.values();
        for (CountDownLatchEnum item: countDownLatchEnums ) {
            if (item.getCode()==index){
                return item;
            }
        }

        return null;
    }
}

package com.wfg.mylock;

import java.util.concurrent.CountDownLatch;

/**
 * javaee
 *
 * @Title: com.wfg.mylock
 * @Date: 2020/9/26 11:34
 * @Author: wfg
 * @Description:
 * @Version:
 */
public class CountDownLatchDemo2 {


    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 1; i <=6; i++) {
            //final int tempi=i;
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"国被灭");
                countDownLatch.countDown();
            },CountDownLatchEnum.foreachEnum(i).getMsg()+"").start();
        }
        countDownLatch.await();
        System.out.println("秦国一统华夏");
    }
}

在这里插入图片描述

2. CyclicBarrier

概念
和CountDownLatch相反,需要集齐七颗龙珠,召唤神龙。也就是做加法,开始是0,加到某个值的时候就执行

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

案例
集齐7个龙珠,召唤神龙的Demo,我们需要首先创建CyclicBarrier

/**
* 定义一个循环屏障,参数1:需要累加的值,参数2 需要执行的方法
*/
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
	System.out.println("召唤神龙");
});

然后同时编写七个线程,进行龙珠收集,但一个线程收集到了的时候,我们需要让他执行await方法,等待到7个线程全部执行完毕后,我们就执行原来定义好的方法

  for (int i = 0; i < 7; i++) {
        final Integer tempInt = i;
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t 收集到 第" + tempInt + "颗龙珠");

            try {
                // 先到的被阻塞,等全部线程完成后,才能执行方法
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }, String.valueOf(i)).start();
    }

完整代码

public class CyclicBarrierDemo1 {

    /**
     * 七珠召唤神龙
     * @param args
     */
    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("神龙出现");
        });

        for (int i = 1; i <=7; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"珠找到");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }



    }
}

在这里插入图片描述

3. Semaphore

概念

信号量主要用于两个目的

  • 一个是用于共享资源的互斥使用
  • 另一个用于并发线程数的控制

代码

我们模拟一个抢车位的场景,假设一共有10个车,3个停车位

那么我们首先需要定义信号量为3,也就是3个停车位

/**
* 初始化一个信号量为3,默认是false 非公平锁, 模拟3个停车位
*/
Semaphore semaphore = new Semaphore(3, false);

然后我们模拟10辆车同时并发抢占停车位,但第一个车辆抢占到停车位后,信号量需要减1

// 代表一辆车,已经占用了该车位
semaphore.acquire(); // 抢占

同时车辆假设需要等待3秒后,释放信号量

// 每个车停3秒
try {
	TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
	e.printStackTrace();
}

最后车辆离开,释放信号量

// 释放停车位
semaphore.release();

完整代码

package com.wfg.mylock;

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

/**
 * javaee
 *
 * @Title: com.wfg.mylock
 * @Date: 2020/9/26 12:09
 * @Author: wfg
 * @Description:
 * @Version:
 */

/**
 * 10个车抢3个停车位
 */
public class SemaphoreDemo1 {

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);

        for (int i = 1; i <=10; i++) {
            new Thread(()->{

                try {
                    //获取资源
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"开始占用车位");
                    try {
                        TimeUnit.SECONDS.sleep(new Random().nextInt(8));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //释放资源
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }
    }

}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值