#CountDownLatch ###是什么 CountDownLatch的字面意思:倒计时 门栓 它的功能是:让一些线程阻塞直到另一些线程完成一系列操作后才唤醒。 它通过调用await方法让线程进入阻塞状态等待倒计时0时唤醒。 它通过线程调用countDown方法让倒计时中的计数器减去1,当计数器为0时,会唤醒哪些因为调用了await而阻塞的线程。
- 底层是使用AQS实现的
###案例 假设老板开一个紧急会议,他先到会议室等着所有人签到然后开始开会,可以使用CountDownLatch进行模拟。
1 public static void main(String[] args) { 2 CountDownLatch countDownLatch=new CountDownLatch(5); 3 4 for (int i=1;i<=5;i++){ 5 new Thread(()->{ 6 System.out.println(Thread.currentThread().getName()+"签到!"); 7 countDownLatch.countDown(); 8 },"第"+i+"個人").start(); 9 } 10 11 12 try { 13 countDownLatch.await(); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 System.out.println("老板宣布人夠了开始开会!"); 18 }
运行结果:
1//注意这里的签到顺序可以随意 2第1個人签到! 3第2個人签到! 4第3個人签到! 5第4個人签到! 6第5個人签到! 7老板宣布人夠了开始开会!
#CyclicBarrier ###是什么 CyclicBarrier [ˈsaɪklɪk] [ˈbæriər] 的字面意思:可循环使用的屏障 【栅栏】 它的功能是:让一组线程到达一个屏障时被阻塞,知道最后一个线程到达屏障,所有被屏障拦截的线程才会继续执行。 它通过调用await方法让线程进入屏障,
-
<span style="color:red;">底层是通过ReentrantLock以及Condition中的await和signal实现</span>
/** The lock for guarding barrier entry / private final ReentrantLock lock = new ReentrantLock(); /* Condition to wait on until tripped */ private final Condition trip = lock.newCondition();
###图例 
###例子 还是上面的开会的例子,我们使用CyclicBarrier实现。
1public static void main(String[] args) { 2 CyclicBarrier cyclicBarrier=new CyclicBarrier(5,()->{ 3 System.out.println("老板宣布人夠了开始开会!!"); 4 }); 5 6 for (int i=1;i<=5;i++){ 7 new Thread(()->{ 8 try { 9 System.out.println(Thread.currentThread().getName()+"签到!"); 10 cyclicBarrier.await(); //如果等待的线程数未到,这里将一直等待 11 //等线程数够了下面语句将继续执行...... 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } catch (BrokenBarrierException e) { 15 e.printStackTrace(); 16 } 17 },"第"+i+"個人").start(); 18 } 19 }
运行结果:
1第1個人签到! 2第2個人签到! 3第3個人签到! 4第4個人签到! 5第5個人签到! 6老板宣布人夠了开始开会!!
#Semaphor ###是什么 Semaphor [ˈseməfɔːr] 信号量的意思; 它主要用于两个目的:
-
用于多个共享资源互斥使用。【也就是具有锁的功能】 一个停车场有多个停车位,这多个停车位对应汽车来说就是多个共享资源,Semaphor可以实现多个停车位和多个汽车之间的互斥。
-
用于控制并发线程数。(就是控制同时得到共享资源的线程数量) 在创建Semaphor时可以指定并发线程数,
1//permits :允许 2public Semaphore(int permits) { 3 sync = new NonfairSync(permits); 4} 5//还可以指定是否为公平锁 6public Semaphore(int permits, boolean fair) { 7 sync = fair ? new FairSync(permits) : new NonfairSync(permits); 8} -
<span style="color:red;">信号量为1时 相当于独占锁 信号量大于1时相当于共享锁。</span>
###例子 我们测试使用Semaphor实现控制线程并发访问方法。
1/** 2 * 测试使用Semaphor信号量控制方法的访问 3 */ 4public class TestSemaphor { 5 Semaphore semaphore=new Semaphore(5); 6 /** 7 * 假设并发只能为5个 8 */ 9 public void pay(){ 10 try { 11 //在 semaphore.acquire() 和 semaphore.release()之间的代码,同一时刻只允许指定个数的线程进入! 12 semaphore.acquire(); 13 System.out.println("这是支付的方法!"); 14 Thread.sleep(2000); 15 semaphore.release(); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 } 20 21 public static void main(String[] args) { 22 TestSemaphor ts=new TestSemaphor(); 23 for (int i=0;i<10;i++){ 24 new Thread(()->{ 25 ts.pay(); 26 },"线程"+i).start(); 27 } 28 } 29}
运行效果:
1线程0这是支付的方法! 2线程3这是支付的方法! 3线程6这是支付的方法! 4线程5这是支付的方法! 5线程1这是支付的方法! 6 7//注意这里是执行的暂停点 8 9线程7这是支付的方法! 10线程8这是支付的方法! 11线程2这是支付的方法! 12线程4这是支付的方法! 13线程9这是支付的方法!
注意结果:10个线程分了两批执行的,也就是说我们控制了访问pay方法的线程数量,每次并发只能是5个!
#CountDownlatch和CyclicBarrier以及Semaphor的区别是
-
CountDownLatch是做减法,CyclicBarrier是做加法,Semaphor的临界资源可以反复使用
-
CountDownLatch不能重置计数,CycliBarrier提供的reset()方法可以重置计数,不过只能等到第一个计数结束。Semaphor可以重复使用。
-
CountDownLatch和CycliBarrier不能控制并发线程的数量,Semaphor可以实现控制并发线程的数量。
#资源 <a href="https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/Multithread/AQS.md#1-aqs-%E7%AE%80%E5%8D%95%E4%BB%8B%E7%BB%8D" target="\_blank">更好的介绍</a>