2012-02-12 45 views
1

考慮下面的代碼:同步使用條件?我怎樣才能使這個代碼的性能和線程安全?

public class SomeClass { 

    private boolean shouldBlock = false; 
    private Object resource; 

    public void handleDrawRequest(Canvas canvas) { 
    if (!shouldBlock && resource == null) 
    { 
     shouldBlock = true; 
     loadTheResource(); //which takes awhile 
     shouldBlock = false; 
    } 
    else if (shouldBlock && resrouce == null) 
    { 
     return; //another thread is taking care of the loading of the resource 
       //and its not ready yet, so just ignore this request 
    } 

    drawResourceOn(canvas); 
    } 
} 

我怎樣才能使此代碼線程安全的?我試圖完成的是隻有一個線程來加載資源,同時任何其他線程試圖同時訪問此代碼將被丟棄(例如,遵循'else if'邏輯)直到資源被加載。可能有很多線程試圖同時訪問這些代碼,我不想同步整個方法並且有一堆線程堆積起來。

回答

2

你正在尋找一個AtomicBoolean

public class SomeClass { 
    // AtomicBolean defaults to the value false. 
    private AtomicBoolean loadingResource = new AtomicBoolean(); 
    private volatile Object resource; 

    public void handleDrawRequest(Canvas canvas) { 
    if (resource == null) { 
     if (loadingResource.compareAndSet(false, true)) { 
     loadTheResource(); //which takes awhile 
     } else { 
     //another thread is taking care of the loading of the resource 
     //and its not ready yet, so just ignore this request 
     return; 
     } 
    } else { 
     drawResourceOn(canvas); 
    } 
    } 
} 
+0

不確定你是否需要資源'volatile'。 – OldCurmudgeon 2012-02-12 01:51:02

+0

看起來不錯,簡單。但是,加載資源可能會失敗,將資源留空,我希望將來的線程能夠重新加載資源。 AtomicReference 可以幫助嗎?或者就像在loadTheResource()之後添加loadingResource.compareAndSet(true,false)一樣簡單? – 2012-02-12 08:31:35

+0

@Chris,如果加載資源失敗,AtomicBoolean可以重置爲false。 – Scorpion 2012-02-12 10:32:39

4

隨着double checkednon-blocking鎖定:

public class SomeClass { 

    private Lock lock = new Lock(); 
    private volatile Object resource; 

    public void handleDrawRequest(Canvas canvas) { 
     if(resource==null) { 
      if(lock.tryLock()) { 
       try { 
        if(resource==null) 
         resource = loadResource(); 
       } 
       finally { 
        lock.unlock(); 
       } 
      } 
      else { 
       return; 
      } 
     } 
     drawResourceOn(canvas); 
    } 
} 

如果你不resourcevolatile,線程可以自由地高速緩存,並可能永遠不會讀取更新後的值。特別是,即使資源在第一個之後加載,第二個空檢查也將始終返回true。

+0

尼斯一個,我創建了一個Eclipse的解決方案,然後發現這個問題的答案張貼:-) – 2012-02-12 03:06:29

+0

@Banthar看起來非常好感謝。你能解釋一下使資源變得不穩定的必要嗎? – 2012-02-12 08:21:26

+1

@ChrisKnight這是爲了確保一個調用'resource = loadResource()'的線程與另一個線程看到一個非空'資源'之間發生的關係。如果沒有'volatile',第二個線程可能會看到一個非null但部分構建的'resource'對象。 – yshavit 2012-02-12 10:16:08