Day35、36 JUC强大的辅助类

我是大白 (●—●) ,这是我开始学习记录大白Java软件攻城狮晋升之路的第三十五、三十六天今天学习的是【尚硅谷】大厂必备技术之JUC并发编程

一、计数器CountDownLatch

概念

CountDownLatch类可以设置一个计数器 ,然后通过countDown方法来进行减1的操作,使用await方法等待计数器不大于0 ,然后继续执行await方法之后的语句。

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

例子

6个同学陆续离开教室后,班长才能关门
不使用CountDownLatch

public class CountDownLatchDemo {
    public static void main (String[] args) {
        //6个同学陆续离开教室之后
        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 ***********班长最后关门走人");
    }
}

会发现结果如下
image.png
在其他同学还没有上完自习,班长就关门了
为了避免以上情况,接下来引入CountDownLatch

package com.example.demo;

import com.example.demo.Enums.CountryEnum;

import java.util.concurrent.CountDownLatch;

/**
 * @author Administrator
 *
 * 让一些线程阻塞直到另一些线程完成一系列操作后才被唤醒
 *
 * CountDownLatch主要有两个方法,当一个或多个线程调用await()方法时,调用线程会被阻塞。
 * 其他线程调用CountDown方法会将计数器减1(调用countDown的方法的线程不会被阻塞),当计数器的值变为0时,因调用await方法的阻塞的线程会被唤醒,继续执行!
 */
public class CountDownLatchDemo {
    public static void main(String[] args) {
        CountDownLatch count = new CountDownLatch(6);
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "\t上完自习,离开教室");
                count.countDown();
            }, String.valueOf(i)).start();
        }
        try {
            //等待
            count.await();
            System.out.println(Thread.currentThread().getName() + "\t ***********班长最后关门走人");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

最终结果如下,可以发现实现了所有线程执行完后,主线程才继续执行:
image.png

二、循环栅栏CyclicBarrier

概念

官方解释:CyclicBarrier是一个同步辅助类,它允许一-组线程互相等待 ,直到到达某个公共屏障点(common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时CyclicBarrier 很有用。因为该barrier在释放等待线程后可以重用,所以称它为循环的barrier。

CyclicBarrier看英文单词可以看出大概就是循环阻塞的意思,在使用中CyclicBarrier的构造方法第一个参数是目 标障碍数,每次执行CyclicBarrier 一次障碍数会加一,如果达到了目标障碍数,才会执行cyclicBarrier.await之后的语句。可以将CyclicBarrier 理解为加1操作。

通俗的讲:CyclicBarrier可以理解为循环栅栏。栅栏就是一种障碍物,比如,通常在私人宅邸的周围可以围上一圈栅栏,阻止闲杂人等入内。这里当然就是用来阻止线程继续执行,要求线程在栅栏外等候。前面Cyclic意为循环,也就是说这个计数器可以反复使用。比如,我们将计数器设置为10,那么凑齐第一批10个线程后,计数器就会归零,接着凑齐下一批10个线程,这就是循环栅栏内的含义。

例子

集齐7颗龙珠就可以召唤神龙

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(7, () -> {
            System.out.println("*******集齐7颗龙珠,召唤神龙");
        });

        for (int i = 1; i <= 6; i++) {
            final int temp = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName()+"\t 收集到第:" + temp + " 颗龙珠");
                try {
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("--------" + temp);
            },String.valueOf(i)).start();
        }
    }
}

结果如下,会发现只收集了6颗龙珠就无法召唤神龙,所有线程都进行了阻塞
image.png
将for循环的边界改为7呢?会发现成功召唤神龙并且执行await方法后的代码。
image.png

三、信号量Semaphore

概念

Semaphore表示一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire() ,然后再获取该许可。每个release()添加一个许可,从而可能释放一个正在阻塞的获取者。 但是,不使用实际的许可对象, Semaphore只对可用许可的号码进行计数,并采取相应的行动。
Semaphore通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。例如下面实例

实例

6辆汽车,去抢3个车位

/**
 * @author Administrator
 *
 * 信号量的主要目的有两个:一个是用于多个共享资源的互斥使用,另一个是用于并发线程数的控制。
 */
public class SemaphoreDemo {
    public static void main(String[] args) {
        //模拟三个停车位
        Semaphore semaphore = new Semaphore(3);
        //模拟六部汽车
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                try {
                    //抢占车位
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "\t 抢到车位");
                    //设置随机停车时间
                    Thread.sleep(1000 + new Random().nextInt(5000));
                    System.out.println(Thread.currentThread().getName() + "\t 离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //释放车位
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }
    }
}

结果如下,表明每次只有三个线程占用Semaphore资源。
image.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值