天天看點

多線程之DownCountLatch CyclicBarrier和Semaphore

一.概述

          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

繼續閱讀