[JUC-07] JUC常用辅助类

1、CountDownLatch

1.1 简介

  CountDownLatchjava.util.concurrent包下的一个工具类。
在这里插入图片描述
  即:这个工具类保存一个数字,不同的线程可以操作这个工具类使得数字减一。简单理解为减法计数器。

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

  CountDownLatch构造器必须输入一个 int 类型数字,作为计数值。

  CountDownLatch有两个核心方法:countDown()await()
  1、countDown():计数值减一;
  2、await():等待计数器归零,然后再向下执行;

1.2 测试

  假设有 10 个同学,要离开教室,人都离开后才能关门。

  先测试不调用countDownLatch.await();的情况:

package pers.klb.myjuc;

import java.util.concurrent.CountDownLatch;

public class AuxiliaryClassTest {
    public static void main(String[] args) throws InterruptedException {
        // 计数值为 10
        CountDownLatch countDownLatch = new CountDownLatch(10);

        // 创建 10 个线程,每个线程都给这个计数值减一
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "--> 离开房间");
                countDownLatch.countDown(); // 计数值减一
            }, String.valueOf(i)).start();
        }

        // 等待计数器归零,若还没归零,则等待
        // countDownLatch.await();

        System.out.println("关门");
    }
}

  运行结果:
在这里插入图片描述
  可见,人还没走完就关门了,增加一个等待:

package pers.klb.myjuc;

import java.util.concurrent.CountDownLatch;

public class AuxiliaryClassTest {
    public static void main(String[] args) throws InterruptedException {
        // 计数值为 10
        CountDownLatch countDownLatch = new CountDownLatch(10);

        // 创建 10 个线程,每个线程都给这个计数值减一
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "--> 离开房间");
                countDownLatch.countDown(); // 计数值减一
            }, String.valueOf(i)).start();
        }

        // 等待计数器归零,若还没归零,则等待
        countDownLatch.await();

        System.out.println("关门");
    }
}

  运行结果:
在这里插入图片描述
  每次线程都调用countDownLatch.countDown()进行减一操作,如果计数值还没归零,countDownLatch.await()会等待,如果归零了,则继续执行。

2、CyclicBarrier

2.1 简介

  CyclicBarrier也是java.util.concurrent包下的一个工具类:
在这里插入图片描述
  可以简单理解为加法计数器。

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

  它的构造器有两个参数:
在这里插入图片描述
在这里插入图片描述
  第一个参数为线程个数,第二个参数是线程达到第一个参数后触发的方法。

  它有一个核心的方法:await(),它的作用是:假设线程数为 N ,每个线程都调用这个方法,当调用这个方法的线程数达到 N 后,触发函数式接口的方法。

2.2 测试

  首先在构造器中设置最大线程数为 7,但是只创建了 6 个线程。

package pers.klb.myjuc;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class AuxiliaryClassTest {

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("召唤神龙");
        });

        for (int i = 1; i <= 6; i++) {
            int num = i;
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + "-> 获取第" + num + "课龙珠");
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

  运行结果:
在这里插入图片描述
  可见,线程数没达到最大值 7,每个线程都处于await()方法中等待。

  如果线程数设置为 7:

package pers.klb.myjuc;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class AuxiliaryClassTest {

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("召唤神龙");
        });

        for (int i = 1; i <= 7; i++) {
            int num = i;
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + "-> 获取第" + num + "课龙珠");
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

  运行结果:
在这里插入图片描述

3、Semaphore

3.1 简介

  Semaphorejava.util.concurrent包下的工具类。
在这里插入图片描述
   在信号量上我们定义两种操作:

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

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

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

3.2 测试

package pers.klb.myjuc;

import java.util.concurrent.*;

/**
 * @program: MyJUC
 * @description: 辅助类
 * @author: Meumax
 * @create: 2020-08-08 17:23
 **/
public class AuxiliaryClassTest {

    public static void main(String[] args) {
        // 创建信号量,数量为 3
        Semaphore semaphore = new Semaphore(3);

        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();    // 获取信号量
                    System.out.println(Thread.currentThread().getName() + "抢到车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release(); // release() 释放
                }
            }, String.valueOf(i)).start();
        }
    }
}

  运行结果:
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值