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.countDown(); // 数量-1 countDownLatch.await(); // 等待计数器归零,然后再向下执行。 每次有线程调用 countDown() 数量-1,假设计数器变为0,countDownLatch.await() 就会被唤醒,继续 执行!
官方文档
构造方法
使用
-
举例:集齐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
还是会指向内存中的常量池内保存的值。 -
那么线程就可以依旧访问的到值。
官方文档
构造方法,其中的许可证指的是信号量
使用方法,在文档中已经给出了,下面做了一个举例
常用方法:
使用
-
举例:抢车位,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 操作,然后唤醒等待的线程!
相当于线程中的通信,只不过封装成了一个工具类