一年前因爲工做須要從微軟技術棧入坑Java,並陸陸續續作了一個Java後臺項目,目前在搞Scala+Java混合的後臺開發,一直以爲併發編程是全部後臺工程師的基本功,因此也學習了小一年Java的併發工具,對總體的併發理解乃至分佈式都有必定的提升,因此想和你們分享一下。java
個人學習路線程序員
首先說說學習路線,我一開始是直接上手JCIP(Java Concurrency in Practice),發現不是很好懂,把握不了那本書的主線,因此思索着從國內的做者開始先,因此便讀了下方騰飛的《Java併發編程的藝術》的,雖然豆瓣上的評價通常,可是對於構建Java併發的總體映像仍是有所提升的,至少我知道了有哪些東西要深刻學習。接着我想增強下併發的理論,繼續讀了The Art of Multiprocessor Programming,這本書比較艱澀,不是很好懂,可是過一遍仍是好處多多,建議初學者瞭解下概念的過過,後期能夠再來翻看。有了以上兩步的支持,接下來就又開始啃JCIP了,發現比之前有了不一樣的感受,我能比較輕鬆的跟上書的脈絡,知道書的總體框架,讀起來不那麼費勁了,這本書號稱Java併發編程的聖經,確實能夠看出做者有很豐富的併發實踐經驗。再後來我過了一遍Oracle官網上的Java Tutorial關於併發的那一章,發現講的也不錯,對於瞭解基礎庫有哪些組件幫助挺大。編程
到了這一步,接下來怎麼繼續提升呢?我發現了一本頗有趣的書,《七週七併發模型》,以前的視野一直是在Java併發編程的工具包中深刻了解,感受,應該跳出來,從模型的角度看看各個語言的併發實現的原理,我目前正處於這一步,發現頗有意思,第一章講Java的線程和鎖這個模型就感受很精髓,只用了小三章把Java總體的脈絡過了一遍,強烈推薦用來複習。緩存
下一步個人計劃是jdk的concurrent包以及Java specification的併發部分,併發理解,除了基礎概念,就是要深入領會各個應用場景下,有無併發問題以及如何寫出線程安全的代碼,我的以爲學習下無鎖的實現對理解有必定的幫助,但不用太費心思,到了Java Memory Model這一層基本就夠用了。安全
根據上面的闡述,個人路線圖能夠總結以下:數據結構
學習心得 -- Java併發包的基礎概念多線程
瞭解Java併發包有哪些工具以及相關基礎概念,有Java tutorial的concurrent章節和JCIP一書就足夠了。併發
JCIP一書的總體脈絡以下:oracle
整體看,該書有兩條主線,1 從高到低介紹Java併發包的一些重要組件和原理; 2 從併發場景出發,介紹如何利用這些組件來得到線程安全。其中第二部分是這本書最大的特點,也是書名中有Practice的緣由。框架
書中提到了幾個比較有意思的地方,
首先,到底什麼是線程安全?
A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.
這個定義中,做者強調了正確地被多線程訪問, 同時要求沒有外加其餘同步的手段。
那麼,如何得到線程安全?
Writing thread-safe code is, at its core, about managing access to state, and in particular to shared, mutable state.
書中將得到線程安全總結爲維護代碼的狀態,若是一個類是無狀態的(immutable),則自帶線程安全的屬性(函數式編程即是經過這種方式達到自帶的線程安全)。這些狀態大體能夠理解爲類中的很是量變量。
經過這個能夠了解到線程安全的本質,實際上是共享變量,也就是狀態,有狀態的多線程訪問就須要同步機制來保證線程安全。
如何理解Java提供的用於處理併發的組件?
JDK提供的併發組件,大體能夠分爲兩類, 一類是預防爲主,防止錯誤發生(race condition, visibility),大部分組件都是這類,還有一類是發生了錯誤可是可以知道並及時重試(Atomic類提供的CAS),形象的例子有如 十字路口的信號燈,在流量小的時候,採用過多的預防措施反而會拔苗助長,例如白白的在大部分時間都沒有車的道路上等紅燈,這個時候適合採用犯錯(例如去掉紅綠燈,讓車自由行駛,遇到其餘車的時候互相讓位便可)後解決的方法,可以得到最大的效率,在流量大的時候,紅綠燈的做用就可以凸顯出來,其實規則的制定必定是在規模較大的時候纔有意義,這也是預防的初衷。
類比到併發領域就是,在線程數量大,採用預防的措施比較好,這樣大部分線程就不會由於機率小的CAS重試浪費大量的cpu週期,在線程數量小的時候,CAS的意義就比較大,由於預防措施帶來的線程切換等的開銷可能大於CAS的等待,並且較少的線程也會讓CAS重試的等待時間變少。
如下是我根據這兩個資料歸納出來的基礎概念,
理解這些基礎概念的核心,我以爲其實就是解決兩點問題:
固然要更深刻理解併發,還須要知道如何提高併發的性能,例如鎖的粒度如何把握?(經典的例子能夠JDK的ConcurrentHashMap),底層一點的知識也得了解,例如CAS和Java Memory Model。
從高維視角瞭解併發
有了Java併發的基礎知識,接下來很適合閱讀七週七併發,我目前就在讀七週七併發,發現站在多種語言從範式的角度瞭解併發頗有意思,原來Java提供的線程和鎖的機制其實至關於比較原始的工具了,其離底層最近。最近接觸了Scala,其使用了AKKA,則是一種高層的併發抽象。
七週七併發試圖從歷史的角度闡述做爲鎖和線程的表明之Java的併發包的進化歷程,首先最先加入JDK的,實際上是synchronized及其statement,可是發現缺乏相關timeout和不能中斷等等功能,加入了可重入鎖,讀寫鎖等等,再後來又加入了各類線程安全的數據結構和高級同步機制。
接下來,七週七併發從函數式編程等等各類範式的角度闡述,除了線程和鎖,還有不少其餘高層抽象能夠更加方便的編寫併發代碼。
這本書對於充分理解併發,拓寬視野頗有幫助,推薦你們閱讀。
從實現角度透徹理解併發
再深刻下去的話,沒有比經典的JDK更合適的了,固然Google的Guava包也值得學習,從這些經典代碼瞭解各類組件的實現能夠加深理解並更好的使用它們,可是做爲應用端的程序員,卻是並不須要寫出這種較爲底層的代碼(無鎖化)。
回顧這小一年的學習曲線,收穫良多,不過最後最值得強調的一點實際上是,在作技術選擇的時候,併發只是工具箱中的一種手段,學習它只是爲了可以靈活運用,設計的首要選擇依然是在當時情境下的最簡化,能不用併發就不要用。