天天看点

多线程之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

继续阅读