敞开生长之旅!这是我参与「日新方案 12 月更文挑战」的第26天,点击检查活动详情
CountDownLatch
概念
CountDownLatch是一个同步东西类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。
CountDownLatch能够使一个线程在等候别的一些线程完结各自作业之后,再持续履行。运用一个计数器进行完成。计数器初始值为线程的数量。当每一个线程完结自己使命后,计数器的值就会减一。当计数器的值为0时,表示一切的线程都现已完结了使命,然后在CountDownLatch上等候的线程就能够恢复履行使命。
CountDownLatch典型用法1:某一线程在开端运转前等候n个线程履行结束。将CountDownLatch的计数器初始化为n new CountDownLatch(n)
,每当一个使命线程履行结束,就将计数器减1 countdownlatch.countDown()
,当计数器的值变为0时,在CountDownLatch上 await()
的线程就会被唤醒。一个典型运用场景便是发动一个服务时,主线程需求等候多个组件加载结束,之后再持续履行。
CountDownLatch典型用法2:完成多个线程开端履行使命的最大并行性。注意是并行性,不是并发,着重的是多个线程在某一时刻一起开端履行。相似于赛跑,将多个线程放到起点,等候发令枪响,然后一起开跑。做法是初始化一个共享的CountDownLatch(1),将其计数器初始化为1,多个线程在开端履行使命前首要 coundownlatch.await()
,当主线程调用 countDown()
时,计数器变为0,多个线程一起被唤醒。
运用
首要运用new CountDownLatch(int count)
结构出一个给定值的计数器。接着运用countDown()
将计数器的值减一,而await()
是时调用的线程被堵塞等候直到计数器的值为0停止。
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()+"\t上完自习,脱离教室");
countDownLatch.countDown();//减一
},String.valueOf(i)).start();
}
countDownLatch.await();//使当时线程等候直到锁存器计数到零停止
System.out.println(Thread.currentThread().getName()+"\t班长关门走人");
}
}
运转检查作用~
CountDownLatch是一次性的,计数器的值只能在结构办法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch运用结束后,它不能再次被运用
CyclicBarrier
概念
现实生活中咱们经常会遇到这样的情形,在进行某个活动前需求等候人全部都齐了才开端。例如吃饭时要等全家人都上座了才动筷子,旅游时要等全部人都到齐了才出发,竞赛时要等运动员都上场后才开端。
在JUC包中为咱们供给了一个同步东西类能够很好的模仿这类场景,它便是CyclicBarrier类。利用CyclicBarrier类能够完成一组线程彼此等候,当一切线程都抵达某个屏障点后再进行后续的操作。下图演示了这一过程。
CyclicBarrier的字面意思是可循环(Cyclic) 运用的屏障(barrier).它要做的工作是,让一组线程抵达一个屏障(也能够叫做同步点)时被堵塞,知道最后一个线程抵达屏障时,屏障才会开门,一切被屏障阻拦的线程才会持续干活,线程进入屏障通过CyclicBarrier的await()办法.
案例
招集7颗龙珠呼唤线程。
public class CyclicBarrierDemo {
public static void main(String[] args) {
//CyclicBarrier(int parties, Runnable barrierAction)
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("呼唤神龙");
});
for (int i = 1; i <= 7; i++) {
final int temp = i;
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"\t收集到第"+temp+"颗龙珠");
try {
//先到了等着
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
CyclicBarrier与CountDownLatch的差异
至此咱们不免会将CyclicBarrier与CountDownLatch进行一番比较。这两个类都能够完成一组线程在抵达某个条件之前进行等候,它们内部都有一个计数器,当计数器的值不断的减为0的时分一切堵塞的线程将会被唤醒。
有差异的是CyclicBarrier的计数器由自己控制,而CountDownLatch的计数器则由运用者来控制,在CyclicBarrier中线程调用await办法不只会将自己堵塞还会将计数器减1,而在CountDownLatch中线程调用await办法只是将自己堵塞而不会减少计数器的值。
别的,CountDownLatch只能阻拦一轮,而CyclicBarrier能够完成循环阻拦。一般来说用CyclicBarrier能够完成CountDownLatch的功用,而反之则不能,例如上面的赛马程序就只能运用CyclicBarrier来完成。总归,这两个类的异同点大致如此,至于何时运用CyclicBarrier,何时运用CountDownLatch,还需求读者自己去拿捏。
除此之外,CyclicBarrier还供给了:resert()、getNumberWaiting()、isBroken()等比较有用的办法。
Semaphore
概念
Semaphore信号量主要用于两个意图,一个是用于多个共享资源的互斥运用。另一个用于并发线程数的控制,用于做限流处理
Seamphore结构办法和ReentrantLock结构办法相似。默许非公正锁,为ture公正锁。
案例
6两轿车抢3个停车位,当3个停车位满时,剩下的三辆车只能走一辆停一辆。
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抢到车位");
//停3秒
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName() + "\t停车三秒后脱离车位");
} catch (Exception e) {
e.printStackTrace();
} finally {
semaphore.release();//开释
}
}, String.valueOf(i)).start();
}
}
}