存在缺陷的代码:
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; } }