本文闡述ConcurrentHashMap線程安全問題,ConcurrentHashMap可以保證多線程讀寫操作時的安全,實際代碼使用時,可能會有以下誤區,從下面的實例代碼中進行演示。
兩個線程分別進行++操作,總共加2000次,核對輸出結果是否是2000;
有誤區的實例代碼
實例代碼如下所示。
package com.yang.concurrent; import java.util.concurrent.ConcurrentHashMap; /** * 錯誤使用ConcurrentHashMap */ public class ErrorUseConcurrentHashMap implements Runnable { private static ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); /** * 這種寫法會導致多線程情況下value是線程不安全的,和ConcurrentHashMap無關 */ @Override public void run() { for (int i = 0; i < 1000; i++) { int value = map.get("tom"); value++; map.put("tom", value); } } public static void main(String[] args) throws InterruptedException { map.put("tom", 0); ErrorUseConcurrentHashMap errorUseConcurrentHashMap = new ErrorUseConcurrentHashMap(); Thread thread1 = new Thread(errorUseConcurrentHashMap); Thread thread2 = new Thread(errorUseConcurrentHashMap); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println("最終輸出值:" + map.get("tom")); } }
輸出結果如下圖:
正確的實例代碼
實例代碼如下圖,我們將上述的代碼優化下。使用CAS的操作方式對其進行優化。
package com.yang.concurrent;
import java.util.concurrent.ConcurrentHashMap;
/**
* 正確使用ConcurrentHashMap
*/
public class CorrectUseConcurrentHashMap implements Runnable {
private static ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
/**
* 此處我們使用CAS操作方式,來替換Synchronized,提供效率
*/
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
while (true){
int oldValue = map.get("tom");
int newValue=oldValue+1;
boolean flag=map.replace("tom",oldValue,newValue);
if (flag){
break;
}
}
}
}
public static void main(String[] args) throws InterruptedException {
map.put("tom", 0);
CorrectUseConcurrentHashMap errorUseConcurrentHashMap = new CorrectUseConcurrentHashMap();
Thread thread1 = new Thread(errorUseConcurrentHashMap);
Thread thread2 = new Thread(errorUseConcurrentHashMap);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("最終輸出值:" + map.get("tom"));
}
}
最終輸出結果: