存在缺陷的代碼:
public class DataPropertyIdAndNameRepositoryImpl{ /** 發布標誌 */ private volatile boolean publishFlag; public Integer getStandardId(int dataId, String propertyName) { if (!publishFlag) { loadToCache(); } Integer standardId = 0; Map<String, Integer> propertyIdMap = propertyIdLocalCache.get(dataId); if (propertyIdMap != null) { standardId = propertyIdMap.get(propertyName); } return standardId; } public synchronized boolean loadToCache() { try { DataPropertyIdAndName dataPropertyIdAndName = dataPropertyIdAndNameService .queryDataPropertyIdAndName(); publishFlag = true; } catch (Exception e) { publishFlag = false; } return publishFlag; }}
存在缺陷的流程:
a. 綠色表示第一個線程,藍色表示第二個線程。
b. 黃色模組的代碼為synchronized標記的代碼,並發情況下只會有一個線程執行此方法。
c. 綠色線程執行到紫色模組時,藍色線程等待進入黃色模組。
d. 藍色線程執行拋異常,導致publishFlag被置為false。
e. 此時再次有線程進入,判斷publishFlag仍為false,因此導致重複不斷載入loadToCache.
修複後的代碼:
public class DataPropertyIdAndNameRepositoryImpl{ /** 發布標誌 */ private volatile boolean publishFlag; public Integer getStandardId(int dataId, String propertyName) { if (!publishFlag) { loadToCache(); } Integer standardId = 0; Map<String, Integer> propertyIdMap = propertyIdLocalCache.get(dataId); if (propertyIdMap != null) { standardId = propertyIdMap.get(propertyName); } return standardId; } public synchronized boolean loadToCache() { try { // 雙檢鎖 if (publishFlag) { return publishFlag; } DataPropertyIdAndName dataPropertyIdAndName = dataPropertyIdAndNameService.queryDataPropertyIdAndName(); publishFlag = true; } catch (Exception e) { publishFlag = false; } return publishFlag; }}