2012-09-26 25 views
2

旗語我需要具有以下特徵的信號:不可重入無阻塞的Java

  1. 應該是非阻塞的,即如果線程不能獲得許可證 它應該走的更遠,而無需等待
  2. 它應該是不可重入,也就是說,如果同一個線程進入代碼的 把守一塊兩次應該拿走2個許可證,而不是 一個

我寫了下面的代碼:

public class SimpleSemaphore 
{ 

    private int permits; 

    private AtomicLong counter = new AtomicLong(); 

    SimpleSemaphore(int permits) 
    { 
     this.permits = permits; 
    } 

    boolean acquire() 
    { 

     if (counter.incrementAndGet() < permits) 
     { 
      return true; 
     } 
     else 
     { 
      counter.decrementAndGet(); 
      return false; 
     } 

    } 

    void release() 
    { 
     counter.decrementAndGet(); 

    } 
} 

另一種選擇是這個信號量:

public class EasySemaphore 
{ 

    private int permits; 

    private AtomicLong counter = new AtomicLong(); 

    EasySemaphore(int permits) 
    { 
     this.permits = permits; 
    } 

    boolean acquire() 
    { 
     long index = counter.get(); 

     if (index < permits) 
     { 
      if (counter.compareAndSet(index, index + 1)) 
      { 
       return true; 
      } 
     } 

     return false; 
    } 

    void release() 
    { 
     counter.decrementAndGet(); 
    } 
} 

是兩種實現線程安全的,對嗎? 哪一個更好? 你將如何去完成這項任務?

回答

7

不是java.util.concurrent.Semaphore已經這麼做了嗎?

它有一個非阻塞獲取的tryAcquire,它保留了剩餘許可證的簡單計數(其中同一個線程可以取多個)。

+0

真的,tryAcquire方法是我所需要的,謝謝!但是,java.util.concurrent.Semaphore的再入口呢?我無法在文檔中找到任何證據表明一條線可能會拿出許多許可證。 – KutaBeach

+0

它在文檔中說沒有跟蹤所有權,只是一個簡單的計數器,並且信號量可以從不同於獲取它的線程釋放。我認爲你的要求是由此而來的。 – Thilo

0

我要說的第二個是更好,因爲計數器永遠不會更大thathan 0(和它的效率更高一點)

我會用一個循環,否則你可以有方法,失敗的時候還有允許左。

public class EasySemaphore { 
    private final AtomicInteger counter; 

    EasySemaphore(int permits) { 
     counter = new AtomicInteger(permits); 
    } 

    boolean acquire() { 
     // highly unlikely to loop more than once. 
     while(true) { 
      int count = counter.get(); 
      if (count <= 0) return false; 
      if (counter.compareAndSet(count, count -1)) 
       return true; 
     } 
    } 

    void release() { 
     counter.incrementAndGet(); 
    } 
}