2015-10-05 28 views
-1

我想了解信號量,並知道信號量維護一套許可證或允許數目的鎖,但仍然有很多疑問。如果信號量如果多個線程試圖鎖定如何行爲

是否允許每個類或整個類本身的實例的鎖的數量保持不變?

我的意思是說,當信號量限制爲2,根據我的代碼,4線程如何獲得鎖。

這是否意味着每個類的實例都會保留許可證。如果是, 那麼它會不會在代碼的狀態中產生不一致?

在下面的代碼運行,輸出如下:

t1 having ts1 acqired lock 
t2 having ts2 acqired lock 
t3 having ts1 acqired lock 
t4 having ts2 acqired lock 
t1 having ts1 released lock 
t4 having ts2 released lock 
t3 having ts1 released lock 
t2 having ts2 released lock 

代碼:

public class SemaphoreTest { 


    public static void main(String[] args) { 
     Task ts1=new Task(); 
     Task ts2=new Task(); 
     Thread t1=new Thread(ts1,"t1 having ts1"); 
     Thread t2=new Thread(ts2,"t2 having ts2"); 
     Thread t3=new Thread(ts1,"t3 having ts1"); 
     Thread t4=new Thread(ts2,"t4 having ts2"); 
     t1.start(); 
     t3.start(); 
     t2.start(); 
     t4.start(); 

    } 
} 

class Task implements Runnable{ 
    Semaphore noOfLocks=new Semaphore(2); 

    @Override 
    public void run() { 
     try { 
      noOfLocks.acquire(); 
      System.out.println(Thread.currentThread().getName() +" acqired lock"); 
      Thread.sleep(1000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     }finally{ 
      noOfLocks.release(); 
      System.out.println(Thread.currentThread().getName() +" released lock"); 
     } 

    } 

} 
+0

你有兩個信號量,每個信號量允許兩個鎖。那是4.我在這裏看不到問題。 – biziclop

+0

這不是我得到的輸出。你的信號量(其中2個)只有1個許可證。一次只能有一個線程訪問每個線程。 –

+0

@biziclop我需要確認每個實例上是否保留允許的鎖的數量。由於我提到了2個鎖,並創建了2個對象,因此4個線程能夠獲取鎖。如果兩個線程獲得同一個對象的鎖定,那麼它們可能會通過嘗試更新同一個實例變量的值而產生一些不一致的狀態。 – user2800089

回答

4

Task類的每個實例有它的一個Semaphore的自己的實例。

class Task implements Runnable { 
    Semaphore noOfLocks=new Semaphore(2); 
    ... 

並且每個信號實例都有自己的許可計數器。

您創建了兩個Task實例,因此您有2個Semaphore實例,每個實例最初有2個許可證。

Task ts1=new Task(); 
    Task ts2=new Task(); 

同時執行多個線程ts1將導致線程同一個信號戰鬥。就像在多個線程中執行ts2一樣。在你的那些代碼:

Thread t1=new Thread(ts1,"t1 having ts1"); 
    Thread t3=new Thread(ts1,"t3 having ts1"); 

Thread t2=new Thread(ts2,"t2 having ts2"); 
    Thread t4=new Thread(ts2,"t4 having ts2"); 

那麼到底有2個線程使用2全許可證次2.沒有需要等待許可證,因爲有足夠的每個人。

如果您想查看某些內容,請使用現有任務創建更多線程或減少初始許可證的數量。

+0

假設在類Task和我的run()方法中有一個hashmap實例變量,我這樣做:if(!hasmap.contains(key)){hashmap.put(key,value)} T1在ts1檢查條件&進入裏面如果阻止。現在CPU從T1切換到T3,它也檢查ts1上的條件並進入If塊。現在我們在IF塊內部有2個線程,這可能導致T1覆蓋T3值,反之亦然,這是不理想的情況。這是如何處理的,或者我的理解有什麼差距。如果它沒有通過信號量處理,那麼它有什麼優勢? – user2800089

+1

@ user2800089如果你用一個只有1個許可證的信號量來保護'if(!h ... lue)}'的整個過程,它就能正常工作。 T3將不得不等待,因爲許可證(從而訪問hashmap)在T1修改它時由T1所有。超過1個許可證的信號量對於保護一次只能由1個線程使用的東西無用,所以通常使用'synchronized'或'ReentrantLock',因爲它們只有1個「許可證」。信號量用於其他場景,例如您有一個數據庫連接池,並且您不希望並行使用多於5個連接。 – zapl

+0

非常感謝。這是我的全部問題,現在已經得到澄清。 – user2800089