CountDownLatch减法计数器演示
public static void main(String[] args) throws InterruptedException {
// 减法计数器, 构造器传入初始的计数值
CountDownLatch countDownLatch = new CountDownLatch(6);
// 模拟7个人,6个学生,1个看门大爷,直到六个学生全部出去,再关门
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "出去了");
countDownLatch.countDown();
System.out.println("ss");
}, String.valueOf(i)).start();
}
// 这个方法的作用: 等待计数器变为0,countDownLatch.await() 唤醒,再往下执行
countDownLatch.await();
System.out.println("close door");
}
CyclicBarrier演示
public static void main(String[] args) {
// 加法计数器,集齐七颗龙珠召唤神龙
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println("成功召唤神龙!!");
});
for (int i = 0; i < 7; i++) {
// 注意这里直接访问i是访问不到的,因为new了一个对象
// 需要一个常量值来作为临时i的替换,再访问
// 当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。
final int temp = i + 1;
new Thread(() -> {
System.out.printf("集齐了%d颗龙珠\n", temp);
// 等待七个线程全部开启,再唤醒
try {
// 调用了await后,内部会自动加1,直到计数到7就会唤醒,继续往下执行
cyclicBarrier.await();
System.out.println("ss");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
Semaphore演示
public static void main(String[] args) {
/**
* 信号量
* 原理:
* acquire(): 获取,如果没有可获取的资源了,等待,等待直到被释放
* release(): 释放,会将当前的信号量释放,然后唤醒等待的线程
* 实例: 3个停车位,6辆车
* 作用: 多个共享资源互斥的使用,并发限流,控制最大的线程数
* 应用: 网络限流
*/
Semaphore semaphore = new Semaphore(3);
// 开启6个线程,相当于6辆车
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
try {
// 获取车位
// System.out.println(Thread.currentThread().getName()+"开始寻求车位");
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "获得了车位!!!");
// 停车2s
TimeUnit.SECONDS.sleep(12);
System.out.println(Thread.currentThread().getName() + "离开了车位!!!");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 释放车位
semaphore.release();
}
}, String.valueOf(i)).start();
}
}