2013-01-09 69 views
2

我有一個線程只有在它獲得2個信號量的獨佔訪問時纔會執行一個動作。java信號量習語

public void run(){ 
      boolean a1=false; 
      boolean a2=false; 
      boolean a3=false; 
      while(true){ 
       try{ 
        if(res[1].tryAcquire()==true){ 
         a1=true; 
         if((res[2].tryAcquire()==true){ 
          a2=true; 
          if(res[3].tryAcquire()==true)){ 
           a3=true; 
           System.out.println("Rolled the tobacco"); 
          } 
         } 
        } 
       } 
       finally{ 
        if(a1){ 
         a1=false; 
         res[1].release(); 
        } 
        if(a2){ 
         a2=false; 
         res[2].release(); 
        } 
        if(a3){ 
         a3=false; 
         res[3].release(); 
        } 
       } 
      } 
     } 
    } 

有沒有更好的方法來寫這個,以確保我們不會打擾信號量獲得計數? 有沒有辦法檢查當前線程是否獲取了信號量?

回答

2

在Java 7中,可以使用Closeable進行嘗試。當然必須有更好的解決方案。

public class Region implements Closeable { 

    private final Semaphore semaphore; 

    public Region(Semaphore semaphore) { 
     this.semaphore = semaphore; 
     if (!semaphore.tryAcquire()) { 
      throw NotAcquiredException(semaphore); 
     } 
    } 

    @Override 
    public void close() { 
     semaphore.release(); 
    } 
} 

public class NotAcquiredException extends Exception { ... } 

用法:

public void run() { 
     boolean a1 = false; 
     boolean a2 = false; 
     boolean a3 = false; 
     while (true) { 
      try (Closeable r1 = new Region(res[1])) { 
       a1 = true; 
       try (Closeable r2 = new Region(res[2])) { 
        a2 = true; 
        try (Closeable r3 = new Region(res[3])) { 
          a3 = true; 
          System.out.println("Rolled the tobacco"); 
        } catch (IOException e) { 
        } 
       } catch (IOException e) { 
       } 
      } catch (IOException e) { 
      } 
     } 
+0

非常好。正如我所看到的,您不允許特別在代碼中修復明顯的錯誤。好。 – Andremoniy

+0

@Andremoniy:「我什麼都沒做」既不拒絕變化,現在thSoft糾正了;感謝兩者。 –

1

你可以分隔每個獲得進入試......終於,不是短,但擺脫了一些變量,使得它很明顯應該發生什麼,每把鎖。 (我改變了基於陣列零)

public void run(){ 
    while(true){ 
     if(res[0].tryAcquire()){ 
      try { 
       if(res[1].tryAcquire()) { 
        try { 
        if(res[2].tryAcquire()){ 
         try { 
          System.out.println("Rolled the tobacco"); 
         } finally { 
          res[3].release(); 
         } 
        } 
        } finally { 
         res[2].release(); 
        }        
       } 
      } finally{ 
       res[1].release(); 
      } 
     } 
    } 
} 

如果您需要獲取大量鎖定或在幾個地方做到這一點,那麼也許一個輔助類將是很好。至少隱藏了獲取和釋放信號量的樣板代碼。

public void run() { 
    SemaphoreHelper semaphoreHelper = new SemaphoreHelper(res); 
    while (true) { 
     try { 
      if (semaphoreHelper.aquireAll()) { 
       System.out.println("Rolled the tobacco"); 
      } 
     } finally { 
      semaphoreHelper.releaseAquired(); 
     } 
    } 
} 

private static class SemaphoreHelper { 

    private final Semaphore[] semaphores; 
    private int semaphoreIndex; 

    public SemaphoreHelper(Semaphore[] semaphores) { 
     this.semaphores = semaphores; 
    } 

    public void releaseAquired() { 
     while (semaphoreIndex > 0) { 
      semaphoreIndex--; 
      semaphores[semaphoreIndex].release(); 
     } 
    } 

    public boolean aquireAll() { 
     while (semaphoreIndex < semaphores.length) { 
      if (!semaphores[semaphoreIndex].tryAcquire()) { 
       return false; 
      } 
      semaphoreIndex++; 
     } 
     return true; 
    } 
}