幾乎每乙個應用都會使用到快取, 但是設計高效的執行緒安全的快取並不簡單. 如:
public inte***ce computable
public class expensivefunction
implements computable
} public class memorizer1implements computable
// 使用synchronized同步整個方法解決執行緒安全
public synchronized v compute(a arg) throws interruptedexception
return result;
} }
memorizer1使用hashmap快取計算結果. 如果能在快取中取出引數對應的結果, 就直接返回快取的資料, 避免了重複進行代價昂貴的計算. 由於hashmap不是執行緒安全的, memorizer1同步整個compute方法, 避免重複計算的同時, 犧牲了併發執行compute方法的機會, 此種設計甚至可能導致效能比沒有快取更差.
使用concurrenthashmap代替hashmap, 同時取消對compute方法的同步可以極大的改善效能:
public class memorizer2implements computable
public v compute(a arg) throws interruptedexception
return result;
} }
concurrenthashmap是執行緒安全的, 並且具有極好的併發效能. 但是該設計仍存在問題: 無法避免所有的重複的計算. 有時這是可以的, 但對於一些要求苛刻的系統, 重複計算可能會引發嚴重的問題. memorizer2的問題在於乙個執行緒在執行compute方法的過程中, 其他執行緒以相同的引數呼叫compute方法時, 無法從快取中獲知已有執行緒正在進行該引數的計算的資訊, 因此造成了重複計算的發生. 針對這一點, 可以改進快取的設計:
public class memorizer3implements computable
public v compute(final a arg) throws interruptedexception
}; futuretaskft = new futuretask(eval);
f = ft;
// 在計算開始前就將future物件存入快取中.
cache.put(arg, ft);
} try catch (executionexception e)
} }
memorizer3中的快取系統看起來已經相當完美: 具有極好的併發效能, 也不會存在重複計算的問題. 真的嗎? 不幸的是memorizer3仍然存在重複計算的問題, 只是相對於memorizer2, 重複計算的概率降低了一些. cache.get(arg)的結果為null, 不代表cache.put(arg, ft)時cache中依舊沒有arg對應的future, 因此直接呼叫cache.put(arg, ft)是不合理的:
public class memorizerimplements computable
public v compute(final a arg) throws interruptedexception
}; futuretaskft = new futuretask(eval);
// 使用putifabsent測試是否真的將ft存入了快取, 如果存入失敗, 說明cache中已經存在arg對應的future物件
// 否則才進行計算.
f = cache.putifabsent(arg, ft);
if (f == null)
} try catch (cancellationexception e) catch (executionexception e)
} }
}
至此才真正實現了高效且執行緒安全的快取.
ps: 終於看完了jcip的第五章, 這一章真是又臭又長...
設計執行緒安全的Servlet
設計執行緒安全的servlet 例項變數和類變數不正確的使用是造成servlet執行緒不安全的主要原因。1 實現 singlethreadmodel 介面 2 同步對共享資料的操作 使用synchronized 關鍵字能保證一次只有乙個執行緒可以訪問被保護的區段,在本 中的servlet可以通過同步...
建立高效的執行緒安全類的步驟
建立高效的執行緒安全類的步驟 編寫執行緒安全類的最簡單的方法是用 synchronized 宣告每個方法。雖然這種方案可以消除資料損壞,但它同時也會消除您預期從多執行緒獲得的任何收益。這樣,您就需要分析並確保在 synchronized 塊內部僅占用最少的執行時間。您必須格外關注訪問緩慢資源 檔案 ...
設計安全的多執行緒應用程式 執行緒安全
以前常聽高手告誡mfc物件不要跨執行緒使用,因為mfc不是執行緒安全的。比如cwnd物件不要跨執行緒使用,可以用視窗控制代碼 hwnd 代替。csocket casyncsocket物件不要跨執行緒使用,用socket控制代碼代替.那麼到底什麼是執行緒安全呢?什麼時候需要考慮?如果程式涉及到多 執行...