CountDownLatch
让一些线程堵塞直到另一个线程完成一系列操作后才被唤醒。CountDownLatch 主要有两个方法,当一个或多个线程调用 await 方法时,调用线程会被堵塞,其他线程调用 countDown 方法会将计数减一(调用 countDown 方法的线程不会堵塞),当计数其值变为零时,因调用 await 方法被堵塞的线程会被唤醒,继续执行。
假设我们有这么一个场景,教室里有班长和其他6个人在教室上自习,怎么保证班长等其他6个人都走出教室在把教室门给关掉。
public class CountDownLanchDemo { public static void main(String[] args) { for (int i = 0; i < 6; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 离开了教室..."); }, String.valueOf(i)).start(); } System.out.println("班长把门给关了,离开了教室..."); } } 0 离开了教室... 1 离开了教室... 2 离开了教室... 3 离开了教室... 班长把门给关了,离开了教室... 5 离开了教室... 4 离开了教室...
发现班长都没有等其他人理他教室就把门给关了,此时我们就可以使用 CountDownLatch 来控制
public class CountDownLanchDemo { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(6); for (int i = 0; i < 6; i++) { new Thread(() -> { countDownLatch.countDown(); System.out.println(Thread.currentThread().getName() + " 离开了教室..."); }, String.valueOf(i)).start(); } countDownLatch.await(); System.out.println("班长把门给关了,离开了教室..."); } }
0 离开了教室...
1 离开了教室...
2 离开了教室...
3 离开了教室...
4 离开了教室...
5 离开了教室...
班长把门给关了,离开了教室...
使用枚举完成countDownLatch案例
@Setter @Getter public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch=new CountDownLatch(6) ; for (int i = 1; i <=6; i++) { new Thread(()->{ System.out.println(Thread.currentThread().getName()+"国被灭......."); countDownLatch.countDown(); },CountryEnum.getcountryEnum(i).getName()+"").start(); } countDownLatch.await(); System.out.println(CountryEnum.seven+"国一统华夏"); } } @Getter enum CountryEnum { one(1, "齐", "100", "demaxiya1"), two(2, "楚", "100", "demaxiya1"), three(3, "燕", "100", "demaxiya1"), four(4, "韩", "100", "demaxiya1"), five(5, "赵", "100", "demaxiya1"), six(6, "巍", "100", "demaxiya1"), seven(7, "秦", "100", "demaxiya1"); private Integer id; private String name; private String time; private String beizhu; CountryEnum(Integer id, String name, String time, String beizhu) { this.id = id; this.name = name; this.time = time; this.beizhu = beizhu; } public static CountryEnum getcountryEnum(Integer id ){ for (CountryEnum value : values()) { if (value.id==id){ return value; } } return null; } }
打印
齐国被灭.......
燕国被灭.......
楚国被灭.......
韩国被灭.......
巍国被灭.......
赵国被灭.......
seven国一统华夏
、CyclicBarrier(集齐七颗龙珠召唤神龙)
-
CycliBarrier
可循环(Cyclic)使用的屏障。让一组线程到达一个屏障(也可叫同步点)时被阻塞,知道最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CycliBarrier的await()方法
-
代码示例:
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class CyclicBarrierDemo { public static void main(String[] args) { cyclicBarrierTest(); } public static void cyclicBarrierTest() { CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> { System.out.println("====召唤神龙====="); }); for (int i = 1; i <= 7; i++) { final int tempInt = i; new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 收集到第" + tempInt + "颗龙珠"); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }, "" + i).start(); } } }
打印2 收集到第2颗龙珠
3 收集到第3颗龙珠
1 收集到第1颗龙珠
5 收集到第5颗龙珠
4 收集到第4颗龙珠
6 收集到第6颗龙珠
7 收集到第7颗龙珠
====召唤神龙=====3、Semaphore信号量
可以代替Synchronize和Lock
-
信号量主要用于两个目的,一个是用于多个共享资源的互斥作用,另一个用于并发线程数的控制
-
代码示例:
抢车位示例:
-
-
package juc.lock.SemaphoreDemo; import java.util.concurrent.Semaphore; /** * @Classname SemaphoreDemo * @Description TODO * @Date 2020/7/13 23:03 * @Created by imp */ public class SemaphoreDemo { public static void main(String[] args) { Semaphore semaphore=new Semaphore(3); //3个车位 for (int i = 0; i < 6; i++) { new Thread(()->{ try { //抢占车位 semaphore.acquire(); System.out.println(Thread.currentThread().getName()+" 抢占到车位"); Thread.sleep(2000); System.out.println(Thread.currentThread().getName()+" 停两秒钟离开"); } catch (InterruptedException e) { e.printStackTrace(); }finally { semaphore.release(); } },String.valueOf(i)).start(); } } }
打印:0 抢占到车位
1 抢占到车位
4 抢占到车位
0 停两秒钟离开
5 抢占到车位
1 停两秒钟离开
4 停两秒钟离开
2 抢占到车位
3 抢占到车位
5 停两秒钟离开
3 停两秒钟离开
2 停两秒钟离开