一、CountDownLatch(倒计时)
基本概念,是什么?
让一个线程await堵塞,直到另一些县城完成一系列操作后才被唤醒;
CountDownLatch主要有2个方法:当一个或者多个线程调用await方法的时候,调用线程将被堵塞;其他线程调用countDown方法将会将计数器减1(调用countDown方法的线程不会堵塞),当计数器变为0的时候,因调用await方法被堵塞的线程将会被唤醒,继续执行。(一个倒计数等待操作)
经典案例:自习室有7个人,1个班长和6个同学,现在的要求是班长必须等到其他6人陆续离开教室后,才可以关门走人 |
1、首先我们先尝试不使用CountDownLatch
package com.jiguiquan.www; public class CountDownLatchDemo { public static void main(String[] args) { for (int i = 0; i < 6; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName()+"\t 上完自习,离开教室"); },String.valueOf(i)).start(); } System.out.println(Thread.currentThread().getName()+"\t *******班长最后关门走人"); } }
执行结果如下:
显然,班长成功将4位同学锁在了教室过夜!
2、使用CountDownLatch
package com.jiguiquan.www; import java.util.concurrent.CountDownLatch; public class CountDownLatchDemo { public static void main(String[] args) throws Exception { CountDownLatch countDownLatch = new CountDownLatch(6); for (int i = 0; i < 6; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName()+"\t 上完自习,离开教室"); countDownLatch.countDown(); },String.valueOf(i)).start(); } countDownLatch.await(); System.out.println(Thread.currentThread().getName()+"\t *******班长最后关门走人"); } }
执行结果如下:
显然,现在流程很正确了;
另一个案例,秦灭六国,一统华夏,使用CountDownLatch和枚举Enum类实现 |
CountryEnum
package com.jiguiquan.www; public enum CountryEnum { ONE(1,"齐"),TWO(2,"楚"),THREE(3,"燕"),FOUR(4,"赵"),FIVE(5,"魏"),SIX(6,"韩"); private Integer retCode; private String retMessage; CountryEnum(Integer retCode, String retMessage) { this.retCode = retCode; this.retMessage = retMessage; } public Integer getRetCode() { return retCode; } public String getRetMessage() { return retMessage; } //根据传进来的数字,获得对应的枚举 public static CountryEnum forEach_CountryEnum(int index) { CountryEnum[] myArray = CountryEnum.values(); //枚举类型天生带着的一个自己的遍历方法; for (CountryEnum item : myArray) { if (index == item.getRetCode()) { return item; } } return null; } }
CountDownLatchDemo2
package com.jiguiquan.www; import java.util.concurrent.CountDownLatch; public class CountDownLatchDemo2 { public static void main(String[] args) throws Exception { CountDownLatch countDownLatch = new CountDownLatch(6); for (int i = 1; i <= 6; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName()+"\t国 被灭"); countDownLatch.countDown(); },CountryEnum.forEach_CountryEnum(i).getRetMessage()).start(); } countDownLatch.await(); System.out.println(Thread.currentThread().getName()+"\t 秦国统一六国"); } }
执行结果:
二、CyclicBarrier(集齐7颗龙珠才能召唤神龙)
基本概念,是什么?
CyclicBarrier的逻辑和CountDownLatch正好相反;字面意思是可循环(Cyclic)使用的屏障(Barrier);
当一组线程达到一个屏障(也可以叫同步点)的时候会被堵塞,直到最后一个线程到达屏障时候,屏障才会打开,所有被屏障拦截的线程才会继续干活;
初始值为0,向上增加到预期时候,才可以执行;
线程进入屏障通过CyclicBarrier的await()方法实现;
经典案例:收集7颗龙珠召唤神龙 |
package com.jiguiquan.www; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class CyclicBarrierDemo { public static void main(String[] args) { //任何接口,如果只包含唯一一个抽象方法,那么它就是一个FI(function interface函数式接口) //要求,函数式接口必须要用lambda表达式,好看 //public CyclicBarrier(int parties, Runnable barrierAction) CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{ System.out.println("召唤神龙"); }); for (int i = 1; i <= 7; i++) { int tempInt = i; new Thread(()->{ System.out.println(Thread.currentThread().getName()+"\t 收集到第"+tempInt+"颗龙珠"); try { cyclicBarrier.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BrokenBarrierException e) { // TODO Auto-generated catch block e.printStackTrace(); } }, String.valueOf(i)).start(); } } }
执行结果:
顺利召唤神龙
三、Semaphore(信号灯,技术信号量)
——停车场(计数方式不像上面2个,一个只减,一个只增,Semaphore有增有减,有减有增,用完归还)
Semaphore信号灯(计数信号量) 主要用于两个目的:
-
一是用于多个共享资源的互斥使用;
-
另一个用于并发线程数的控制;
经典案例:6部车进3个车位的停车场 |
package com.jiguiquan.www; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; public class SemaphoreDemo { public static void main(String[] args) { Semaphore semaphore = new Semaphore(3); //模拟3个停车位 for (int i = 1; i <= 6; i++) { //模拟6部汽车 new Thread(() -> { try { semaphore.acquire(); //(抢占成功)打出这行,代表一部车已经占到一个车位了 System.out.println(Thread.currentThread().getName()+"\t 抢到车位"); //暂停一会儿线程,代表车在这儿停一段时间 TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName()+"\t 停车3秒钟后离开车位"); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } },String.valueOf(i)).start(); } } }
执行结果:
很显然,先抢到车位的3部车,在使用过程中,456另外3部车在场外等待;
在前三部车停完3秒钟后,会归还车位,然后另外三部车又迅速进来;
Semaphore有借有还,这种特性在以后的线程池中使用,可以达到非常完美的效果!
1 Comment
你好