java多線程(三)-同步工具Semaphore

       Semaphore也是一個線程同步的輔助類,可以維護當前訪問自身的線程個數,並提供了同步機制。使用Semaphore可以控制同時訪問資源的線程個數,例如,實現一個文件允許的併發訪問數。
Semaphore的主要方法摘要:
  void acquire():從此信號量獲取一個許可,在提供一個許可前一直將線程阻塞,否則線程被中斷。
  void release():釋放一個許可,將其返回給信號量。
  int availablePermits():返回此信號量中當前可用的許可數。

  boolean hasQueuedThreads():查詢是否有線程正在等待獲取。

代碼實例:

public class SemaphoreTest {
	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		final  Semaphore sp = new Semaphore(3);
		for(int i=0;i<10;i++){
			Runnable runnable = new Runnable(){
					public void run(){
					try {
						sp.acquire();
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					System.out.println("線程" + Thread.currentThread().getName() + 
							"進入,當前已有" + (3-sp.availablePermits()) + "個併發");
					try {
						Thread.sleep((long)(Math.random()*10000));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("線程" + Thread.currentThread().getName() + 
							"即將離開");					
					sp.release();
					//下面代碼有時候執行不準確,因爲其沒有和上面的代碼合成原子單元
					System.out.println("線程" + Thread.currentThread().getName() + 
							"已離開,當前已有" + (3-sp.availablePermits()) + "個併發");					
				}
			};
			service.execute(runnable);			
		}
	}

}
效果部分截圖:

                                                   

       單個信號量的Semaphore對象可以實現互斥鎖的功能,並且可以是由一個線程獲得了“鎖”,再由另一個線程釋放“鎖”,這可應用於死鎖恢復的一些場合。

如下情景:現成程序中的Test類中有10個線程來消費生成者產生的數據,這些消費者都調用TestDo.doSome()方法去進行處理,故每個消費者都需要一秒才能處理完,程序應保證這些消費者線程依次有序地消費數據,只有上一個消費者消費完後,下一個消費者才能消費數據,下一個消費者是誰都可以,但要保證這些消費者線程拿到的數據是有順序的。

代碼如下:

import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;

public class Test {

	public static void main(String[] args) {
		final Semaphore semaphore = new Semaphore(1);
		final SynchronousQueue<String> queue = new SynchronousQueue<String>();
		for(int i=0;i<10;i++){
			new Thread(new Runnable(){
				@Override
				public void run() {	
					try {
						//從此信號量獲取一個許可,在提供一個許可前一直將線程阻塞,否則線程被中斷。
						semaphore.acquire();
					
						String input = queue.take();
						String output = TestDo.doSome(input);
						System.out.println(Thread.currentThread().getName()+ ":" + output);
						//釋放一個許可,將其返回給信號量。						
						semaphore.release();
					
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}	
				}
			}).start();
		}
		
		System.out.println("begin:"+(System.currentTimeMillis()/1000));
		for(int i=0;i<10;i++){  
			String input = i+"";  
			try {
				//加入到隊列
			
				queue.put(input);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

class TestDo {
	public static String doSome(String input){
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		String output = input + ":"+ (System.currentTimeMillis() / 1000);
		return output;
	}
}
效果圖:

                                     

另外線程的其他同步工具有CyclicBarrier,CountDownLatch,Exchanger以及同步集合(併發集合)在java.util.concurrent包下的ConcurrentHashMap,CopyOnWriteArrayList,CopeyOnWriteArraySet。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章