古人云 (無圖無真相, 有美女走光圖爲證):
引用
Pat-a-map, Pat-a-map, maker's man,
Make me a map as fast as you can...
這集要講的工具叫
MapMaker.
顧名思義, MapMaker就是幫你作Map滴, 並且是as fast as it can! 實在是居家旅行, 製做Map的必備工具啊!
但是啊, 這計算機一思考, 你就笑了: "小樣兒, 作Map還用你作啊? 當我文盲?" 不就是:
new HashMap<姓名, 獎金>()
嘛. 若是用上回書提到的Maps就是:
Maps.newHashMap();
再不, 用ImmutableMap, 就是
ImmutableMap.of("ajoo", 10000000000000000);
計算機: 這個, 這個, 啊, (耳語: 老大, 別這麼不給面子啊. 出來混都不容易), 咱們這裏講的不是HashMap, 也不是ImmutableMap, 實際上是表明着當代最最高科技的
java.util.concurrent.ConcurrentMap
, 它適合多線程操做, 高併發, 無阻塞, 無死鎖, 無衝突, 無測漏, 無...
你: 等等, 你是在說:
new ConcurrentHashMap<姓名, 獎金>()
這麼簡單到離譜的東西麼?
計算機: 這個, 別急, 別急. 其實不徹底是. MapMaker提供了更多更強大的功能. 好比能夠指定鍵是否用弱引用, 指定一個鍵多長時間過時之類的. 可是最最最有用的, 是那個
makeComputingMap()函數.
畫面一轉, ajoo平易近人地微笑着說: 對啦! 這也就是我今天要講MapMaker的主要緣由.
你們想想, 平時有沒有須要作延遲初始化(所謂lazy initialization)和緩存的? 好比說, 我要對每個須要用到的員工名字經過數據庫查詢她一年以來的加班多少, 加班是否自覺自願, 漂亮程度, 身材和三圍指標, 領會領導意圖能力, 幫領導擋酒總加侖數等等等等各類數據, 最後通過一個NP問題的近似解決算法來獲得員工的獎金數額.
這個東西算起來太費資源, 弄很差比獎金自己還多. 那麼, 就要延遲計算, 只有員工主動跑來跟我要加薪, 我纔去算. 並且要緩存, 若是這個員工對只發50元獎金心存不滿, 反覆來吵鬧, 甚至投訴, 咱們不用從新計算.
通常若是你本身寫怎麼寫呢? 假設我那個算獎金的函數寫好了, 就叫computeBonus(姓名). 這樣麼?
class BonusManager {
private final Map<姓名, 獎金> cache = new HashMap<姓名, 獎金>();
獎金 getBonus(姓名 name) {
獎金 bonus = cache.get(name);
if (bonus == null) {
bonus = computeBonus(name); // 危險在這裏!
}
cache.put(name, bonus);
return bonus;
}
}
其實主要邏輯是這樣的. 問題是這個實現不是多線程安全的.
你能夠在getBonus()上面加一個synchronized關鍵字, 而後它就線程安全了. 可是, 讓咱們假設咱們是個跨國知名連鎖大托拉斯, 須要極高極高的併發能力.
聰明如你必定會想到把HashMap改爲ConcurrentHashMap.
近了一步了, 可是還不徹底. 這是由於兩個線程可能同時執行if (bonus == null)而後同時去運行computeBonus(). 結果是, 咱們可能對某些名字重複運行computeBonus(). 讓咱們再假設老闆遇到這種你給公司浪費了資源的狀況會炒你魷魚的.
呵呵, 到這裏, 若是你想到了雙檢查鎖機制(所謂的
double-checked locking), 那算你狠, 遇到大家這種聰明到煞風景的聽衆我真是無話可說, 捲簾朝散, 請假還宮!
而若是你沒想到, 那麼, 恭喜你, 你答對啦! 獎河南雙匯火腿腸一根(94年珍藏版).
我想說的, 實際上是, 俺也不知道怎麼寫最好. 因此呀, 最好是不寫. 反正MapMaker都給咱寫好了不是? 人生苦短, 當及時行樂啊, 同志! 有閒功夫多洗幾塊尿布好很差?
那麼, 不賣關子了 (等不及已經看了javadoc文檔的同志們都已經本身寫出來了. 俺再搖頭晃腦故做玄虛恐怕就要吃臭雞蛋, 爛西紅柿伺候咯). 請看. 噹噹噹當 (貝多芬第九交響曲響起)!
ConcurrentMap<名字, 獎金> cache = new MapMaker()
// 若是一個計算一年有效 (嗯, 明年獎金減半!), 那麼設一個過時時間
.expiration(365, TimeUnit.DAYS)
.makeComputingMap(new Function<名字, 獎金>() {
@Override public 獎金 apply(名字 name) {
return computeBonus(name);
}
});
就是這麼簡單. 等等, 我先擺個pose先, 樣子屌不屌? 這裏面惟一須要解釋的就是這個Function. 你們都知道, java是一門羅唆的語言藝術, 講究說學逗唱, 不是, 說錯了, 講究類, 方法, 表達式, 匿名類等等等等, 反正是怎麼寫累人怎麼來. 這裏的目的其實就是告訴makeComputingMap()怎樣"compute". 這個function是個匿名類, 它的apply()函數封裝了怎麼計算這麼一個概念. (哎呀, 手都打酸了) 而後, makeComputingMap()就接手過去, 它內部怎麼搞的咱不關心, 反正我上面想要的功能它全實現了, 這就夠了唄. 行了, 洗尿布去了. 未完待續