好久沒寫文章了,最近有種深深的危機感,準備打打雞血,溫故以前看過但是工作中很少用到的知識點。
CopyOnWrite寫時複製,JDK中一共有兩個類CopyOnWriteArrayList和CopyOnWriteArraySet。
顧名思義,就是隻有容器中內容被修改的時候,就會copy出一個容器,然後在這個新的容器裏改,之後將原容器的引用指向這個新的容器;好處就是對這個容器進行併發讀寫操作的時候,不需要額外加鎖。
從以上源碼看到,讀的時候,並沒有加鎖,讀的是原容器的數據,所以當正在寫入的時候,讀的可能是舊數據。
以上這種,本人在實際項目中的確使用過,但是並沒有使用CopyOnWrite,而是自己通過加鎖來實現的,大家看以下代碼:
public static volatile Map<String, String> MAP_URL = new HashMap<String, String>();
public void urlRefresh() {
Map<String, Object> paramMap = new HashMap<String, Object>();
// paramMap.put(MapUrlMapper.id, "");
List<MapUrl> list = mapUrlMapper.find(paramMap);
if (list != null && list.size() > 0) {
Map<String, String> tempUrl = new HashMap<String, String>();
for (MapUrl mu : list) {
String orderSyncKey = Constants.MAP_URL_PREFIX_ORDER_SYNC + mu.getAreaCoding();
String memberSyncKey = Constants.MAP_URL_PREFIX_MEMBER_SYNC + mu.getAreaCoding();
String yunwifiOnoffSyncKey = Constants.MAP_URL_PREFIX_YUN_WIFI_ONOFF_SYNC + mu.getAreaCoding();
String orderSyncUrl = mu.getOpenInformationUrl();
String memberSyncUrl = mu.getMemberSyncUrl();
String yunwifiOnoffSyncUrl = mu.getWifiOnoffUrl();
if (StringUtils.isNotEmpty(orderSyncUrl)) {
tempUrl.put(orderSyncKey, orderSyncUrl);
}
if (StringUtils.isNotEmpty(memberSyncUrl)) {
tempUrl.put(memberSyncKey, memberSyncUrl);
}
if (StringUtils.isNotEmpty(yunwifiOnoffSyncUrl)) {
tempUrl.put(yunwifiOnoffSyncKey, yunwifiOnoffSyncUrl);
}
}
OverAllVar.MAP_URL = tempUrl;
logger.info("刷新URL數據 {}", OverAllVar.MAP_URL);
} else {
OverAllVar.MAP_URL.clear();
}
}
可以看到,作用和CopyOnWrite是一樣的。
使用CopyOnWrite因爲存在數據的複製,必然會導致內存佔用增加,增加GC的次數,所以大家在使用時酌情考慮。