一.概述
DownCountLatch ,CyclicBarrier和Semaphore都是共享鎖,但是他們達到的效果不一樣
DownCountLatch :DownCountLatch 讓一個線程等待,等其他線程運作某一個條件後,這個線程才可以繼續運作。DownCountLatch在執行個體話的時候可以傳這個int類型的資料count,count是鎖計數器,隻有當count等于0的時候,等待的線程才能運作下去。當一個線程調用DownCountLatch的await方法的時候,這個線程會處于等待狀态,要想讓這個線程拿到共享鎖繼續運作下去,就得讓其他線程調用countDown方法,每個線程調用countDown方法一次,count就會減一,當count減到0為止,這個線程才會繼續運作下去。
CyclicBarrier:CyclicBarrier是讓N個線程互相等下去。在執行個體化CyclicBarrier的時候會給它傳一個int類型的參數N,隻有N個線程都運作到CyclicBarrier的await方法的時候,這些線程才能繼續運作下去。也就是說目前面N-1個線程運作到await方法的時候,N-1個線程都是等待的狀态,隻有當第N個線程運作await方法的時候,這N個線程才是處于就緒狀态。
Semaphore:在執行個體化Semaphore的時候,會傳一個int類型的參數count,count就代表着Semaphore的信号池中有Semaphore個信号量,當一個線程調用Semaphore的acquire()或acquire(n)方法的時候就是擷取1個或n個信号量,Semaphore的信号池就會減去這個線程擷取到的信号量,當其他線程再調用acquire(m)方法擷取信号量的時候,Semaphore信号池的中的信号量個數大于m,這個線程就可以繼續運作,當信号池中的信号量小于m,這個線程就會處于等待狀态,等待擁有信号量的線程調用release(n)方法釋放自己所擁有的的信号,等信号池的信号量大于等于索要的信号量時,這個線程才會繼續運作下去。
二.舉例
1.DownCountLatch舉例說明
package wangbiao.test.runnable;
import java.util.concurrent.CountDownLatch;
/**
* 共享鎖CountDownLatch舉例
* @author 作者 wangbiao
* @date 建立時間:2017年6月12日 下午6:21:28
* @parameter
* @return
*/
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException{
CountDownLatch countDownLatch = new CountDownLatch(5);
System.out.println(Thread.currentThread().getName()+" start");
for(int i=0;i<5;i++){
RunnableDemo runnableDemo = new RunnableDemo(countDownLatch);
Thread thread = new Thread(runnableDemo,i+"");
thread.start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+" end");
}
}
class RunnableDemo implements Runnable{
CountDownLatch countDownLatch;
public RunnableDemo(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run(){
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"========start");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
運作結果:
main start
2========start
0========start
4========start
1========start
3========start
main end
main線程在運作到21行的countDownLatch.await()代碼時會處于等待狀态,其他的五個線程即使在運作過程中都暫停了2秒,但main線程還是等其他五個線程都調用了countDownLatch的countDown()方法後,main線程才繼續運作下去。
2.cyclicBarrier舉例說明
package wangbiao.test.runnable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
/**
* @author 作者 wangbiao
* @date 建立時間:2017年6月12日 下午8:06:18
* @parameter
* @return
*/
public class CyclicBarrierTest {
public static void main(String[] args) throws Exception{
CyclicBarrier cyclicBarrier = new CyclicBarrier(5,new Runnable(){
public void run(){
System.out.println("cyclicBarrier 觸發的事件");
}
});
for(int i=0;i<5;i++){
RunnableDemoTwo runnableDemoTwo = new RunnableDemoTwo(cyclicBarrier);
Thread thread = new Thread(runnableDemoTwo,i+"");
thread.start();
}
}
}
class RunnableDemoTwo implements Runnable{
CyclicBarrier cyclicBarrier;
public RunnableDemoTwo(CyclicBarrier cyclicBarrier){
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run(){
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+"========start");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName()+"========end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
運作結果:
3========start
4========start
0========start
2========start
1========start
cyclicBarrier 觸發的事件
1========end
3========end
0========end
4========end
2========end
當線程0,1,2,3,4中的前3個線程運作到41行cyclicBarrier的await()方法的時候,這3個線程都是處于等待狀态的,當第4個線程運作完await()方法的時候,會觸發cyclicBarrier中的預置線程,然後這四個線程就是進入就緒狀态去競争cpu然後運作下去。當然也可以不用設定cyclicBarrier的預置線程,那這四個線程就直接是就緒狀态了。
3.Semaphore舉例說明
package wangbiao.test.runnable;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;
/**
* @author 作者 wangbiao
* @date 建立時間:2017年6月12日 下午8:33:39
* @parameter
* @return
*/
public class SemaphoreTest {
public static void main(String[] args){
Semaphore semaphore = new Semaphore(10);
RunnableDemoThree runnableDemoThree1 = new RunnableDemoThree(semaphore,5);
RunnableDemoThree runnableDemoThree2 = new RunnableDemoThree(semaphore,3);
RunnableDemoThree runnableDemoThree3 = new RunnableDemoThree(semaphore,7);
Thread thread1 = new Thread(runnableDemoThree1,1+"");
Thread thread2 = new Thread(runnableDemoThree2,2+"");
Thread thread3 = new Thread(runnableDemoThree3,3+"");
thread1.start();
thread2.start();
thread3.start();
}
}
class RunnableDemoThree implements Runnable{
Semaphore semaphore;
int i;
public RunnableDemoThree(Semaphore semaphore,int i){
this.semaphore = semaphore;
this.i = i;
}
@Override
public void run(){
try {
semaphore.acquire(i);
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"========end");
} catch (Exception e) {
e.printStackTrace();
}finally {
// 釋放給定數目的許可,将其傳回到信号量。
semaphore.release(i);
System.out.println(Thread.currentThread().getName()+"========i:"+i);
}
}
}
運作結果:
2========end
1========end
2========i:3
1========i:5
3========end
3========i:7
線程1,2,3運作到第40行的semaphore.acquire(i)方法的時候,semaphore信号池的信号量是10,線程1和線程2分别擷取了5個和3個信号量,線程池的限号量還剩2個,等線程3再去擷取7個信号量的時候就會處于等待狀态,線程3隻有等待線程1和線程2運作到47行的semaphore.release(i)時,線程3才能擷取到足夠的信号量,才能繼續運作下去。
以上是我對CountDownLatch,CyclicBarrier和Semaphore這個共享鎖最基本的了解,希望能幫到你。如果你想更深入的去了解這幾個共享鎖的原理,可以看看下面的連結
參考連結:
http://www.cnblogs.com/skywang12345/p/3533887.html
http://www.cnblogs.com/skywang12345/p/3533995.html
http://www.cnblogs.com/skywang12345/p/3534050.html