簡體   English   中英

這是在靜態方法中使單例映射線程安全的正確有效方法嗎?

[英]Is this the correct and efficient way to make a singleton map thread safe in a static method

我只想在地圖初始化時創建一次鎖。 這是我正在使用的代碼。

public static Map<String, String> getOrderStatusInstance() {
    if (orderStatusMap == null) {
        synchronized (Utility.class) {
            orderStatusMap = new HashMap<String, String>();

            orderStatusMap.put("Key1", "Value1");
            orderStatusMap.put("Key2", "Value2");
            orderStatusMap.put("Key3", "Value3");
            orderStatusMap.put("Key4", "Value4");
        }
    }

    return orderStatusMap;
}

不,那是個壞主意-您將返回一個可變的,非線程安全的映射。 您還嘗試實現雙重檢查鎖定,但未正確執行-與使用靜態初始化相比,要使其正確無誤。

我將創建一個不可變的映射(使用Guava作為首選項),理想情況下,應作為類初始化的一部分:

private static final ImmutableMap<String, String> STATUS_MAP = ImmutableMap.of(
    "Key1", "Value1",
    "Key2", "Value2",
    "Key3", "Value3",
    "Key4", "Value4");

public static ImmutableMap<String, String> getOrderStatusInstance() {
    return STATUS_MAP;
}

(對於超過5個鍵/值對,請使用ImmutableMap.Builder 。)

您是否真的需要比這更懶惰?

幾乎是正確的...考慮一個線程檢查orderStatusMap == null並變為true的情況。 然后,調度程序切換到另一個執行相同檢查的線程。 沒有兩個線程都將執行同步塊。

通過在同步塊中再次檢查null來防止這種情況:

if (orderStatusMap == null) {
    synchronized (Utility.class) {
        if (orderStatusMap == null) {
            Map<String, String> tmp = new HashMap<String, String>();

            tmp.put("Key1", "Value1");
            tmp.put("Key2", "Value2");
            tmp.put("Key3", "Value3");
            tmp.put("Key4", "Value4");

            orderStatusMap = tmp;
        }
    }
}
return orderStatusMap;

是的,這樣做兩次就可以了。 外部檢查仍然有助於提高性能,因為在創建映射后,無需再執行進入同步塊的昂貴步驟。

請記住,這是創建哈希圖的線程安全方法。 它不會使映射成為線程安全的。

PS:如果您喜歡這個問題,您可能還會喜歡: 如何直接初始化HashMap(以字面方式)?

您應該再次檢查synchronized塊內是否為null

當兩個線程調用您的方法時,它們都將發現orderStatusMap為null,其中一個將在synchronized塊內,而另一個將在塊內。 但最終它將在同步塊內傳遞並再次初始化映射。

不,這是不正確的

沒有必要在這里進行延遲初始化(我相信無論如何都應該過度使用),所以只需執行以下操作:

private static final Map<String, String> orderStatusMap;
static{
    orderStatusMap = Collections.synchronizedMap(new HashMap<String, String>());//making it thread safe
    //or use a ConcurrentHashMap

    orderStatusMap.put("Key1", "Value1");
    orderStatusMap.put("Key2", "Value2");
    orderStatusMap.put("Key3", "Value3");
    orderStatusMap.put("Key4", "Value4");
}

public static Map<String, String> getOrderStatusInstance() {
    return orderStatusMap;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM