JUC下countDownLatch、CyclicBarrier、Semaphore以及枚举的常见使用方法
枚举类
@Getter public enum CountryEnum { ONE(1, "燕"), TWO(2,"赵"), THREE(3,"韩"), FOUR(4,"魏"), FIVE(5,"齐"), SIX(6,"楚"); private Integer code; private String mess; CountryEnum(Integer code, String mess) { this.code = code; this.mess = mess; } public static CountryEnum forEachCountryEnum(int index){ CountryEnum[] values = CountryEnum.values(); for (CountryEnum e : values) { if (index == e.getCode()){ return e; } } return null; } }
1、countDownLatch
countDownLatch是在java1.5被引入,跟它一起被引入的工具类还有CyclicBarrier、Semaphore、concurrentHashMap、BlockingQueue。
存在于java.util.cucurrent包下。
countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
是通过一个计数器来实现的,计数器的初始值是线程的数量。
每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,
然后在闭锁上等待的线程就可以恢复工作了。
即:当一个或多个线程调用await()方法时,调用线程会被阻塞,其它线调用countDown()会将计数器减1(调用countDown()方法的线程不会被阻塞),
当计算器的值变为0时,因调用await()方法被阻塞的线程会被唤醒,继续执行;
代码示例:(未使用countDownLatch类)
public class CountDownLatchDemo { public static void main(String[] args) throws Exception { for (int i = 1; i <= 6; i++) { new Thread(() ->{ System.out.println(Thread.currentThread().getName()+"\t国:被灭;"); },CountryEnum.forEachCountryEnum(i).getMess()).start(); } System.out.println(Thread.currentThread().getName()+"\t***大秦帝国一统华夏***"); } }
代码示例:(使用countDownLatch类)
public class CountDownLatchDemo { public static void main(String[] args) throws Exception { CountDownLatch countDownLatch = new CountDownLatch(6);//初始值 6个线程 for (int i = 1; i <= 6; i++) { new Thread(() ->{ System.out.println(Thread.currentThread().getName()+"\t国:被灭;"); countDownLatch.countDown();//线程数 -1 },CountryEnum.forEachCountryEnum(i).getMess()).start(); } countDownLatch.await();//main线程等待,当countDownLatch值为0时放开; System.out.println(Thread.currentThread().getName()+"\t***大秦帝国一统华夏***"); } }
2、CyclicBarrier
CyclicBarrier的字面意思是可循环(Cyclic)使用的屏障(Barrier)。他要做的事情是让一组线程到达一个屏障(也可以叫同步点)时被阻塞;
直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截下来的线程才会继续执行,线程进入屏障通过CyclicBarrier的await()方法;
public class CyclicBarrierDemo { //CyclicBarrier(int parties) //创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待它时,它将跳闸,并且当屏障跳闸时不执行预定义的动作。 //CyclicBarrier(int parties, Runnable barrierAction) //创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待时,它将跳闸,当屏障跳闸时执行给定的屏障动作,由最后一个进入屏障的线程执行。 public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> { System.out.println("***召唤神龙***"); }); for (int i = 1; i <= 7; i++) { final int finalI = i; new Thread(() -> { System.out.println(Thread.currentThread().getName() + "\t 收集到第:" + finalI + "颗龙珠"); try { cyclicBarrier.await();//阻塞等待 } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }, String.valueOf(i)).start(); } } }
3、Semaphore
信号量主要用于两个目的,一个用于多个共享资源的互斥作用,另一个用于并发线程数的控制;
Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。
使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。
/** * public Semaphore(int permits)创建一个 Semaphore与给定数量的许可证和非公平公平设置。 * 参数 * permits - permits的初始许可证。 该值可能为负数,在这种情况下,必须在任何获取被授予之前发布释放。 * <p> * public Semaphore(int permits,boolean fair)创建一个 Semaphore与给定数量的许可证和给定的公平设置。 * 参数 * permits - permits的初始许可证。 该值可能为负数,在这种情况下,必须在任何获取被授予之前发布释放。 * fair - true如果这个信号量将保证首先在竞争中首先授予许可证,否则 false */ public class SemaphoreDemo { public static void main(String[] args) { Semaphore semaphore = new Semaphore(3);//模拟三个停车位 for (int i = 1; i <= 6; i++) {//模拟6部车 new Thread(() -> { try { semaphore.acquire();//从该信号量获取许可证,阻止直到可用,或线程为 interrupted(被中断) 。 System.out.println(Thread.currentThread().getName() + "\t抢到车位"); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() + "\t停车3秒后离开车位"); } catch (Exception e) { e.printStackTrace(); } finally { semaphore.release();//释放许可证,将其返回到信号量。 } }, String.valueOf(i)).start(); } } }