zoukankan      html  css  js  c++  java
  • 7、常用的辅助类(必会)

    CountDownLatch 减法计数器

    官方文档介绍

    使用

    • 举例:教室里有6个人,门卫需要等到人走完了才会去关门

    • 开启6个线程作为人,计数器判断线程执行完毕后,才会执行接下去的代码。

    package com.zxh.add;
    
    import java.util.concurrent.CountDownLatch;
    
    public class CountDownLatchDemo {
        public static void main(String[] args) throws InterruptedException {
            // 计数器,设置总数为6
            CountDownLatch countDownLatch = new CountDownLatch(6);
    // 教室里有6个人
            for (int i = 1; i <= 6; i++) {
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName() + "离开了教室");
                    countDownLatch.countDown(); // 总数 -1
                }, String.valueOf(i)).start();
            }
    
            countDownLatch.await(); //等待总数变为0,才会被唤醒,接下去执行
            System.out.println("门卫关门");
        }
    }

    • 如果没有countDownLatch.await(),计数器不会等待,执行顺序就会乱

    原理

    countDownLatch.countDown(); // 数量-1
    countDownLatch.await(); // 等待计数器归零,然后再向下执行。
    每次有线程调用 countDown() 数量-1,假设计数器变为0,countDownLatch.await() 就会被唤醒,继续
    执行!

    CyclicBarrier加法计数器

    官方文档

     构造方法

    使用

    • 举例:集齐7颗龙珠

    • 就是有7个线程,每个线程执行完毕后,都等待其他线程达到屏障,就是调用一下await()方法

    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    public class CyclicBarrierDemo {
        public static void main(String[] args) {
            // 等待7个线程都操作了这个await方法到达屏障后,就会执行另一个线程
            CyclicBarrier cyclicBarrier = new CyclicBarrier(7, ()->{
                System.out.println("集齐7颗龙珠,召唤神龙成功!");
            });
    
            for (int i = 1; i <= 7; i++) {
                final int temp = i;
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName() + "集齐了" + temp + "颗龙珠");
                    try {
                        cyclicBarrier.await();  // 该线程调用await(),到达屏障
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }
    }

    注意点

    final int temp = i;

    线程操作的变量为什么要变成一个常量?

    • 外部变量可能会在线程还没有执行完毕时,就销毁了。

    • 那么就给创建一个新的变量temp等于外部变量,获取到外部变量的值,并且添加final修饰符,就会将值存储在常量池中,temp变量指向它。

    • 匿名内部类使用的是temp变量,值和外部变量相同。

    • 当外部变量销毁时,也就是生命周期结束后,这个temp还是会指向内存中的常量池内保存的值。

    • 那么线程就可以依旧访问的到值。

    Semaphore信号量

    官方文档

     构造方法,其中的许可证指的是信号量

     使用方法,在文档中已经给出了,下面做了一个举例

     常用方法:

    使用

    • 举例:抢车位,6个车子抢3个车位

    • 这里把信号量比作车位,6个车子比作线程

    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);
    
            // acquire()获得资源
            // relase()释放资源
            for (int i = 1; i <= 6; i++) {
                new Thread(()->{
                    try {
                        semaphore.acquire();    // 获取信号量,也就是对信号量的 -1 操作,如果没有信号量,则等待
                        System.out.println(Thread.currentThread().getName() + "抢到车位");
                        TimeUnit.SECONDS.sleep(2);  // 模拟车子停了一段时间
                        System.out.println(Thread.currentThread().getName() + "离开了车位");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        semaphore.release();    // 释放资源,返回信号量,也就是 +1 操作,唤醒等待的线程
                    }
                }, String.valueOf(i)).start();
            }
        }
    }

    原理

    资源 相当于 信号量

    semaphero.acquire()获取资源,假如资源已经分配完了,也就是说车位满了,就会等待,等待资源被释放!

    semaphero.release():释放资源,会将当前的信号量释放,就是 +1 操作,然后唤醒等待的线程!

    相当于线程中的通信,只不过封装成了一个工具类

    作用:多个共享资源互斥的使用!并发限流,控制最大的线程数!保障系统的安全

    致力于记录学习过程中的笔记,希望大家有所帮助(*^▽^*)!
  • 相关阅读:
    swift 动画
    WCF身份验证二:基于消息安全模式的自定义身份验证
    WCF身份验证一:消息安全模式之<Certificate>身份验证
    SQL Server 事务与锁
    C# 6.0 的新特性
    SQL Cursor 游标的使用
    C# 几种读取MAC地址的方法
    C# 获取方法所在的 命名空间 类名 方法名
    SQL Server 日志清除
    C# 利用WMI对象获取物理内存和可用内存大小
  • 原文地址:https://www.cnblogs.com/zxhbk/p/12957326.html
Copyright © 2011-2022 走看看