Java并发编程小总结:CountDownLatchCyclicBarrier和Semaphore
Posted shijianhenjinpo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java并发编程小总结:CountDownLatchCyclicBarrier和Semaphore相关的知识,希望对你有一定的参考价值。
Java并发编程小总结:CountDownLatch、CyclicBarrier和Semaphore
这几个类都是在JUC下,也就是java.util.concurrent包下。
这两天学习了一下并发编程中的三个类的使用和一些应用场景,所以做一下记录和总结,方便自己日后再查看复现。
1、CountDownLatch。
这个类的核心思想总结为8个字“秦灭6国,一统华夏”。它可以实现的是一个类似计数器的功能,与CyclicBarrier的思想正好相反。是一个减法操作。
CountDownLatch有且只有一个构造器,且默认提供此构造器,设置初始值的时候必须大于0,否则就会抛异常,可看源码图。
public void await() throws InterruptedException { }; //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行。此方法的位置在真正执行任务之前。
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行。此方法的位置在真正执行任务之前。
public void countDown() { }; //每次线程执行完一次操作后可以将count值减1。如我们例子中灭掉一个国家就执行一次操作--。
public long getCount() {return sync.getCount();} //返回当前计数。
当秦要实现一统华夏的目的,必须把所有的6国都得全部的灭掉之后才可以统一。实行的是一个减法操作。
public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(6); long count = countDownLatch.getCount(); System.out.println(count); for (int i = 1; i <= 6; i++) { new Thread(() ->{ System.out.println(Thread.currentThread().getName() + " 国,被干掉"); countDownLatch.countDown(); }, CountryEnum.forEach_countryEnum(i).getCountry()).start(); } countDownLatch.await(); System.out.println(" "+ Thread.currentThread().getName() + " *************秦帝国,一统华夏"); } }
执行结果:
6
齐 国,被干掉
楚 国,被干掉
燕 国,被干掉
秦 国,被干掉
韩 国,被干掉
魏 国,被干掉
main *************秦帝国,一统华夏
2、CyclicBarrier。
这个类的核心思想也总结为8个字“集齐龙珠,召唤神龙”,与CountDownLatch的思想正好相反,是一个加法操作。
CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
CyclicBarrier的构造器设置的时候初始值也必须大于0。
参数barrierAction为当这些线程都达到barrier状态时会执行的内容。
public int await() throws InterruptedException, BrokenBarrierException { };// 调用await()方法的线程会被挂起,直到所有线程都达到状态时才会执行的任务。
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };//和await()类似,只不过等待一定时间后还有线程未达到状态也不管了,直接执行任务。
有一个reset方法,可以重置计数。还有一些方法暂未被关注。
当要实现召唤神龙的目的,必须把7颗龙珠都集齐才可以执行。实行的是一个加法操作。
public class CyclicBarrierDemo { public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(7,() ->{ System.out.println("龙珠已经集齐,开始召唤神龙啦******************"); }); cyclicBarrier.reset(); for (int i = 1; i <= 7; i++) { int finalI = i; new Thread(() ->{ System.out.println("获得第" + finalI + "颗龙珠"); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }).start(); } } }
执行结果:
获得第1颗龙珠
获得第5颗龙珠
获得第4颗龙珠
获得第3颗龙珠
获得第2颗龙珠
获得第6颗龙珠
获得第7颗龙珠
龙珠已经集齐,开始召唤神龙啦******************
3、Semaphore
这个类翻译过来叫做 信号量 ,可以通俗的理解为一个阻塞队列,只是可以控制同时进入的线程数。通过 acquire() 获取资格,如果没有就等待,当获取到资格执行完任务后可以 release() 退出资格。
Semaphore提供了2个构造器,//参数permits表示许可数目,即同时可以允许多少线程进行访问。//参数fair表示是否是公平的,不会的请自行百度公平和非公平锁。
public void acquire() throws InterruptedException { } //获取一个资格
public void acquire(int permits) throws InterruptedException { } //获取某个指定的资格
public void release() { } //释放当前资格
public void release(int permits) { } //释放指定的资格
这4个方法获取不到都会阻塞,直到获取成功为止。如果想要立刻直到结果可以使用tryAcquire()方法来确认。
public boolean tryAcquire() { }; //尝试获取一个资格,若获取成功,则立即返回true,否则立即返回false
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException { }; //尝试获取一个资格,增加了一个超时功能,在指定时间内获得则立即返回true,否则则立即返回false
public boolean tryAcquire(int permits) { }; //尝试获取指定的资格,若获取成功,则立即返回true,否则立即返回false
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException { }; //尝试获取指定资格,增加了一个超时功能,若在指定的时间内获取成功则立即返回true,否则则立即返回false
通过availablePermits()方法得到可用的许可数目。
public class SemaphoreDemo { public static void main(String[] args) { Semaphore semaphore = new Semaphore(5); for (int i = 1; i <= 8; i++) { int finalI = i; new Thread(() ->{ try { semaphore.acquire(); System.out.println(finalI +"--号工人进来使用机器"); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(finalI +"号工人退出使用机器--"); semaphore.release(); } }).start(); } } }
执行结果:
2--号工人进来使用机器
4--号工人进来使用机器
1--号工人进来使用机器
3--号工人进来使用机器
5--号工人进来使用机器
5号工人退出使用机器--
3号工人退出使用机器--
4号工人退出使用机器--
8--号工人进来使用机器
2号工人退出使用机器--
1号工人退出使用机器--
7--号工人进来使用机器
6--号工人进来使用机器
8号工人退出使用机器--
6号工人退出使用机器--
7号工人退出使用机器--
-----------------------------------------------------------------------------------------------------------------------------------------------------
下面对上面说的三个辅助类进行一个总结:
1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:
CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;
而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;
另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。
2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。
这里是参考博主-Matrix海子 大神的case https://www.cnblogs.com/dolphin0520/p/3920397.html
及观看 机构《尚硅谷》阳哥视频,做的小总结。
以上是关于Java并发编程小总结:CountDownLatchCyclicBarrier和Semaphore的主要内容,如果未能解决你的问题,请参考以下文章