2013-12-18 189 views
3

我對java.util.concurrent包中的「Semaphore」類感到困惑。這裏是我的代碼片段:對Semaphore類感到困惑

import java.util.concurrent.Semaphore; 

public class TestSemaphore { 
    public static void main(String[] args){ 
     Semaphore limit = new Semaphore(2); 
     SemaphoreAA s = new SemaphoreAA(limit); 
     AAThread a = new AAThread(s); 
     Thread[] sThread = new Thread[100]; 
     for(int i = 0; i<100; i++){ 
      sThread[i] = new Thread(a,"[sThread"+i+"]"); 
      sThread[i].start(); 

     } 
    } 
} 

class SemaphoreAA{ 
    private static int counter; 
    private Semaphore limit; 

    public SemaphoreAA(Semaphore limit){ 
     this.limit = limit; 
    } 

    public void increment() throws InterruptedException{ 
     System.out.printf("%-15s%-25s%5d%n",Thread.currentThread().getName()," : Before Increment. Current counter: ",counter); 
     limit.acquire(); 
     System.out.printf("%-15s%-25s%n",Thread.currentThread().getName()," : Get the resource. Start to increment."); 
     counter++; 
     System.out.printf("%-20s%-40s%5d%n",Thread.currentThread().getName()," : Increment is done. Current counter: ",counter); 
     limit.release(); 
    } 
} 

class AAThread implements Runnable{ 
    private SemaphoreAA s; 

    public AAThread(SemaphoreAA s){ 
     this.s = s; 

    } 

    public void run() { 
     try { 
      s.increment(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 

我知道它可以用來控制對資源的訪問。如果我將限制設置爲1,就像這個「信號量限制=新的信號量(1)」,它看起來像是一個鎖。它被證明。如果將限制設置爲2,我預計在給定時間內有兩個線程可以訪問increment()方法,並且可能會導致數據競爭。輸出可能是這樣的:

  • [sThread3]:之前遞增。當前計數器:2
  • [sThread4]:增量前。當前計數器:2
  • [sThread3]:獲取資源。開始增加。
  • [sThread4]:獲取資源。開始增加。
  • [sThread3]:增量完成。當前計數器:3
  • [sThread4]:遞增完成。當前計數器:3

不過,雖然我已經試了好幾次,並沒有出現預期的結果。所以我想知道我是否誤解了它。謝謝。

+0

你應該把循環放在run()方法中 - 啓動線程需要時間並減少交錯的可能性... – assylias

+0

它在一個線程@assylias – RamonBoza

+0

@RamonBoza每個線程只運行一條指令's.increment ()'所以啓動線程的時間實際上比「增量」的時間要長得多 - 爲了有機會觀察交錯和競速,你需要及時調用「增量」。例如在每個線程中調用「increment」10000次。 – assylias

回答

3

你明白了吧。

但是,雖然我已經嘗試了幾次,但預期的結果並沒有發生。

僅僅因爲它可以出現並不意味着它會。這是大多數併發錯誤的問題:它們有時會出現,有時不會。

如果您想要增加發生錯誤的可能性,您可以增加Thread的數量,或者在兩個不同的循環之後創建/啓動它們。

+0

我得到了你,這就是爲什麼我已經嘗試了幾次,並將線程數增加到100(而不是10)來捕獲預期結果。但是,它沒有工作。 – franksunnn

+0

然後使用兩個循環。預先創建'Thread'對象。 –

+1

@franksunn嘗試在增值之前將值賦予局部變量,然後執行if(local + 1!= counter){fail();在這種情況下,你可以一遍又一遍地運行它,直到它最終失敗。 –