java多線程之Semaphore信號量詳解

   信號量在操做系統中通常用來管理數量有限的資源.每類資源有一個對應的信號量.信號量的值表示資源的可用數量.在使用資源時,要先從該信號量上獲取一個使用許可.成功獲取許可以後,資源可用數量減1.在持有許可期,使用者能夠對獲取資源進行操做.完成對資源的使用以後,須要在信號量上釋放一個許可,資源可用數加1,容許其餘使用者獲取資源.當資源可用數爲0的時候,須要獲取資源的線程以阻塞的方式來等待資源變爲可用,或者過段時間以後再檢查資源是否變爲可用.

   在java中有相應的Semaphore實現類,在建立Semaphore類的對象時指定資源的可用數,經過acquire方法以阻塞式的方式獲取許可,而tryAcquire方法以非阻塞式的方式來獲取許可.當須要釋放許可時,使用release方法.Semaphore類也支持同時獲取和釋放多個資源的許可.經過acquire方法獲取許可的過程是能夠被中斷的.若是不但願被中斷,那麼可使用acquireUninterruptibly方法.Semaphore也支持在分配許可時使用公平模式,經過把構造方法的第二個參數設置爲true來使用該模式.在公平模式下,當資源可用時,等待線程按照調用acquire方法申請資源的順序依次獲取許可.在進行資源管理時,通常使用公平模式,以免形成線程飢渴問題.須要注意的是獲取資源時,經過synchronized關鍵詞或鎖聲明同步.這是由於Semaphore類只是一個資源數量的抽象表示,並不負責管理資源對象自己,可能有多個線程同時獲取到資源使用許可,所以須要使用同步機制避免數據競爭.

使用信號量管理資源的示例:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import  java.util.*;
import  java.util.concurrent.ExecutorService;
import  java.util.concurrent.Executors;
import  java.util.concurrent.Semaphore;
import  java.util.concurrent.locks.ReentrantLock;
 
/**
  * 信號量使用詳解,使用信號量來管理有限的資源
  * User: ketqi
  * Date: 2013-01-27 12:29
  */
public  class  SemaphoreDemo {
     /** 可重入鎖,對資源列表進行同步 */
     private  final  ReentrantLock lock =  new  ReentrantLock();
     /** 信號量 */
     private  final  Semaphore semaphore;
     /** 可以使用的資源列表 */
     private  final  LinkedList<Object> resourceList =  new  LinkedList<Object>();
 
     public  SemaphoreDemo(Collection<Object> resourceList) {
         this .resourceList.addAll(resourceList);
         this .semaphore =  new  Semaphore(resourceList.size(),  true );
     }
 
     /**
      * 獲取資源
      *
      * @return 可用的資源
      * @throws InterruptedException
      */
     public  Object acquire()  throws  InterruptedException {
         semaphore.acquire();
 
         lock.lock();
         try  {
             return  resourceList.pollFirst();
         finally  {
             lock.unlock();
         }
     }
 
     /**
      * 釋放或者歸還資源
      *
      * @param resource 待釋放或歸還的資源
      */
     public  void  release(Object resource) {
         lock.lock();
         try  {
             resourceList.addLast(resource);
         finally  {
             lock.unlock();
         }
 
         semaphore.release();
     }
 
     public  static  void  main(String[] args) {
         //準備2個可用資源
         List<Object> resourceList =  new  ArrayList<>();
         resourceList.add( "Resource1" );
         resourceList.add( "Resource2" );
 
         //準備工做任務
         final  SemaphoreDemo demo =  new  SemaphoreDemo(resourceList);
         Runnable worker =  new  Runnable() {
             @Override
             public  void  run() {
                 Object resource =  null ;
                 try  {
                     //獲取資源
                     resource = demo.acquire();
                     System.out.println(Thread.currentThread().getName() +  "\twork   on\t"  + resource);
                     //用resource作工做
                     Thread.sleep( 1000 );
                     System.out.println(Thread.currentThread().getName() +  "\tfinish on\t"  + resource);
                 catch  (InterruptedException e) {
                     e.printStackTrace();
                 finally  {
                     //歸還資源
                     if  (resource !=  null ) {
                         demo.release(resource);
                     }
                 }
             }
         };
 
         //啓動9個任務
         ExecutorService service = Executors.newCachedThreadPool();
         for  ( int  i =  0 ; i <  9 ; i++) {
             service.submit(worker);
         }
         service.shutdown();
     }
}
相關文章
相關標籤/搜索