2017-07-28 69 views
2

您如何看待我們是否需要使用同步塊進行更好的優化訪問Ad實例? Ad.class的實例可以從不同的線程中獲取。同步有助於通過ConcurrentHashMap中的一個獲取操作一次獲取實例。 ConcurrentHashMap將所有值存儲爲volatile。我在java 1.7上使用它爲android,computeIfAbsent在java 1.8中可用。ConcurrentHashMap作爲單點緩存與同步

這將是很好的得到詳細的答案,爲什麼不或爲什麼是。 謝謝!

public final class Ad { 

    private final static Map<String, Ad> ads = new ConcurrentHashMap<>(); 

    public static Ad get(@NonNull String appId) { 
     if (appId == null) appId = ""; 

     boolean containsAd = ads.containsKey(appId); 

     Ad localInstance = containsAd ? ads.get(appId) : null; 

     if (localInstance == null) { 
      synchronized (Ad.class) { 

       containsAd = ads.containsKey(appId); 

       localInstance = containsAd ? ads.get(appId) : null; 

       if (localInstance == null) { 
        localInstance = new Ad(); 
        localInstance.setAdId(appId); 
        ads.put(appId, localInstance); 
       } 
      } 
     } 
     return localInstance; 
    } 

    private Ad() { 
    } 
} 

UPDATE:感謝所有的幫助。我將ConcurrentHashMap替換爲HashMap。

+0

如果你讀的Javadoc,這個類的目的是防止鎖定。同步塊沒有意義。您可以使用散列表 – efekctive

+0

是的,如果您發現自己同時使用'synchronized'和'ConcurrentHashMap',那麼您要麼沒有正確使用'ConcurrentHashMap',要麼應該使用非線程安全集合。 –

回答

1

這並不十分理想。如果多個線程同時嘗試初始化值,那麼即使他們正在查找不同的密鑰,它們也會相互阻塞。

您應該使用ConcurrentHashMap.computeIfAbsent檢查添加並在一個步驟中創建缺少的。這樣,你就不會創建不使用任何廣告,如果他們試圖初始化同一條目兩個線程只會阻止對方:我瞭解你真正想達到什麼

public static Ad get(@NonNull String appId) { 
    if (appId == null) appId = ""; 

    return ads.computeIfAbsent(appId, Ad::new); 
} 

private Ad(String appId) { 
    this(); 
    setAdId(appId); 
} 
+0

謝謝@ matt-timmermans,這很有道理。 這是否意味着當我在一個線程中創建一個新的廣告並將其放到ConcurrentHashMap中以獲取當前密鑰時,其他線程將被阻止? 對不起,我忘了寫我在java 1.7上使用它的android。 computeIfAbsent在java 1.8中可用(((( –

+0

)只有試圖創建廣告的線程(在同一個*或不同的*鍵上)將被阻止,所以如果沒有太多密鑰也不算太壞 –

0

從爲putIfAbsent並且因爲這是這種簡單然後你做什麼(你使用的是雙重檢查鎖定):

public static Ad get(String appId) { 
    String newId = appId == null ? "" : appId; 
    ads.putIfAbsent(newId, new Ad()); 
    return map.get(newId); 
} 
+0

使用此代碼,如果地圖沒有「appId」映射,那麼'Ad.get()'會返回'null',我不認爲這是理想的 –

+0

如果'newId'不存在於map中,'putIfAbsent ''會返回'null',你的'get()'方法也會返回'null'。 –

+0

@SeanBright哦,該死!我正在考慮'computeIfAbsent(newId,s - > new Ad())',但寫了一個完全不同的東西 - 謝謝你糾正我,但這顯然不是原子了 – Eugene