[英]Is following code Thread safe
我有一個場景,我必須維護一個可以由多個線程填充的Map,每個線程都修改相應的List(唯一標識符/鍵是線程名稱),當線程的列表大小超過固定批量大小時,我們必須保持DB中的記錄。
示例代碼如下:
private volatile ConcurrentHashMap<String, List<T>> instrumentMap = new ConcurrentHashMap<String, List<T>>();
private ReadWriteLock lock ;
public void addAll(List<T> entityList, String threadName) {
try {
lock.readLock().lock();
List<T> instrumentList = instrumentMap.get(threadName);
if(instrumentList == null) {
instrumentList = new ArrayList<T>(batchSize);
instrumentMap.put(threadName, instrumentList);
}
if(instrumentList.size() >= batchSize -1){
instrumentList.addAll(entityList);
recordSaver.persist(instrumentList);
instrumentList.clear();
} else {
instrumentList.addAll(entityList);
}
} finally {
lock.readLock().unlock();
}
}
每隔2分鍾就會再運行一個單獨的線程來保存Map中的所有記錄(以確保每隔2分鍾后我們會持續存在一些內容並且地圖大小不會太大)並且當它啟動時它會阻止所有其他線程(檢查readLock和writeLock usawhere writeLock具有更高的優先級)
if(//Some condition) {
Thread.sleep(//2 minutes);
aggregator.getLock().writeLock().lock();
List<T> instrumentList = instrumentMap .values().stream().flatMap(x->x.stream()).collect(Collectors.toList());
if(instrumentList.size() > 0) {
saver.persist(instrumentList);
instrumentMap .values().parallelStream().forEach(x -> x.clear());
aggregator.getLock().writeLock().unlock();
}
這個解決方案幾乎適用於我們測試的每個場景,除非有時候我們看到一些記錄丟失了,盡管它們在Map中添加得很好但根本沒有保留
我的問題是這段代碼有什么問題? ConcurrentHashMap不是最好的解決方案嗎? 讀/寫鎖的使用在這里有問題嗎? 我應該順序處理嗎?
不,這不是線程安全的。
問題是您正在使用ReadWriteLock的讀鎖定。 這並不保證進行更新的獨占訪問權限。 您需要使用寫鎖定。
但是你根本不需要使用單獨的鎖。 您只需使用ConcurrentHashMap.compute
方法:
instrumentMap.compute(threadName, (tn, instrumentList) -> {
if (instrumentList == null) {
instrumentList = new ArrayList<>();
}
if(instrumentList.size() >= batchSize -1) {
instrumentList.addAll(entityList);
recordSaver.persist(instrumentList);
instrumentList.clear();
} else {
instrumentList.addAll(entityList);
}
return instrumentList;
});
這允許您更新列表中的項目,同時還保證對給定鍵的列表的獨占訪問權限。
我懷疑您可以將compute
調用拆分為computeIfAbsent
(如果不存在則添加列表),然后是computeIfPresent
(更新/持久化列表):這里不需要這兩個操作的原子性。 但是將它們分開並沒有真正的意義。
另外, instrumentMap
幾乎肯定不應該是易變的。 除非你真的想重新分配它的價值(給定這個代碼,我懷疑),刪除volatile並使其成為最終。
同樣,非最終鎖也是有問題的。 如果你堅持使用鎖定,也要做到最后。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.