一、setifabsent方法的介紹
setifabsent方法是ConcurrentMap介面中的一種方法,它可以在ConcurrentMap中添加一個鍵-值對,但只有在該鍵不存在時,才能添加成功。如果該鍵已經存在,則setifabsent方法不會添加該鍵-值對。
/** * 如果指定的鍵不存在,則將指定的值與鍵關聯。如果該鍵已經存在,則此方法不執行任何操作並返回當前的值。 * * @param key 鍵 * @param value 值 * @return 可能為null的之前的價值,如果沒有值映射,則為null */ V putIfAbsent(K key, V value);
和put方法的不同點在於setifabsent方法只有在鍵不存在時才會添加值,而put方法無論鍵是否存在都會添加。
二、setifabsent方法的使用場景
setifabsent方法最適用於多線程應用場景,特別是在ConcurrentMap中,多線程同時訪問並修改同一個鍵時,使用setifabsent方法可以保證操作的原子性,避免多個線程同時添加相同的鍵-值對。
另外,setifabsent方法的返回值為之前該鍵的舊值,如果該鍵不存在,則返回null。這個特性可以用於實現一些有用的功能,比如計數器和緩存。
三、使用示例
1. 線程安全的計數器
假設我們需要統計一個網站的訪問次數,考慮以下這段代碼:
ConcurrentHashMap<String, Integer> counter = new ConcurrentHashMap(); public void count(String page) { if (counter.containsKey(page)) { counter.put(page, counter.get(page) + 1); } else { counter.put(page, 1); } }
count方法中使用了containsKey、put和get方法,雖然這段代碼看起來沒什麼問題,但由於ConcurrentHashMap是一個線程安全的容器,在多線程並發訪問的情況下,會存在競態條件,從而導致結果不準確。
為了保證計數器的正確性,我們可以使用setifabsent方法,將上面的代碼修改為以下形式:
ConcurrentHashMap<String, Integer> counter = new ConcurrentHashMap(); public void count(String page) { Integer count = counter.putIfAbsent(page, 1); if (count != null) { counter.put(page, count + 1); } }
在使用setifabsent方法後,只有一個線程可以添加相同的鍵-值對,其他線程會被阻塞,直到添加完成,這樣計數器的結果就是準確的了。
2. 線程安全的緩存
如果我們需要實現一個緩存,在多線程並發訪問的情況下,也需要保證緩存的正確性和性能。假設我們使用ConcurrentHashMap作為緩存容器,代碼如下:
ConcurrentHashMap<String, String> cache = new ConcurrentHashMap(); public String get(String key) { String value = cache.get(key); if (value == null) { value = expensiveOperation(key); cache.put(key, value); } return value; } private String expensiveOperation(String key) { // some expensive operation }
get方法中使用了get、put和null判斷,這段代碼在單線程環境下沒有問題,但在多線程並發訪問的情況下,會存在競態條件,從而導致緩存結果不準確。
為了保證緩存的正確性和性能,我們可以使用setifabsent方法,將上面的代碼修改為以下形式:
ConcurrentHashMap<String, String> cache = new ConcurrentHashMap(); public String get(String key) { String value = cache.get(key); if (value == null) { String newValue = expensiveOperation(key); value = cache.putIfAbsent(key, newValue); if (value == null) { value = newValue; } } return value; } private String expensiveOperation(String key) { // some expensive operation }
在使用setifabsent方法後,只有一個線程可以添加相同的鍵-值對,其他線程會被阻塞,直到添加完成,這樣緩存的結果就是準確的了。另外,由於ConcurrentHashMap是線程安全的,所以使用setifabsent方法可以保證緩存的性能。
原創文章,作者:UDSGR,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/371795.html