最近在總結《Java多線程編程核心技術》這本書。實話實說:多線程編程核心技術,這些字眼屬實有些誇大。面試
可是也不能由於此,就直接否定了書籍自己的價值。這是一篇比較適合入門閱讀的書籍。和我最近在嘗試寫的文章有類似之處,也就是盡力讓知識點,少思考性而多閱讀性。編程
所以接下來會將這本書的內容,揉到個人接下來的文章中,旨在:真正能在碎片化時代下,進行有效學習。安全
愛因斯坦:「若是你不能簡單地解釋同樣東西,說明你沒真正理解它。」多線程
[短文速讀-2] 重載/重寫,動/靜態分派?(從新修訂)工具
[短文速讀-3] 內部匿名類使用外部變量爲何要加finalpost
[短文速讀 -5] 多線程編程引子:進程、線程、線程安全學習
毫無疑問,一切的開始。確定是先介紹介紹概念性的東西。主題是線程,可是談到線程,勢必不能忘了進程。所以讓咱們先來聊一聊線程和進程的概念。操作系統
接下來讓咱們有請文章一向的主角:小A和MDove出場~
小A:MDove,我最近在思考一個問題,多線程多線程。那到底什麼是多線程呢?
MDove:想要理解多線程,其實就要不得不提一提:進程,以及進程和線程之間的關係。
一個比較通俗且常見的解釋:進程:操做系統分配資源的基本單位;線程:操做系統調度最小單位。
稍稍學院派的解釋:
來自《如今操做系統(第4版)》 + 維基百科 + 百度百科
小A:哦?既然進程是程序的實體,那麼只要進程不就好了?
MDove:這固然是沒有問題啦。可是,一個致命的問題,你們都追求快,更快,很是快!
小A:不不不不不,我就追求慢,堅挺~
MDove:堅挺是吧,你這麼秀,你怎麼不去Tokyo Hot?擱這給我扯犢子。學不學了?不學你去找加藤鷹去。
小A:學學學,個人理解:是否是線程比進程佔用資源更少?
MDove:其實關於消耗資源這個問題很難回答。好比Linux、Windows對進程和線程的設計就是不一樣的。若是從Linux的角度出發,進程和線程不管是建立仍是上下文切換其實不在極端狀況下,所謂的性能仍是資源,差距並非很大。差距比較大的一點是:進程是內存獨立,而線程內存共享。
MDove:固然,兩者均可以悄摸得去作一些事情,但不一樣點在於:進程間通信,遠比線程間通信複雜的。所以在上層高級語言的設計上,線程便成了不錯的用於後臺完成耗時操做的一個工具。可是不能否認的一點,多進程一樣扮演者舉足輕重的角色!打個比方,單進程的程序,若是殺死這個進程那麼這個進程所依附的全部線程所有死亡。而多進程則不怕,畢竟彼此是獨立運行的進程,所以多進程在拉活方面有着不俗的戰鬥力。
小A:哦~原來如此,那能夠聊一聊線程麼?
MDove:好的,接下來讓咱們看一看線程。
MDove:舉個小例子:打開咱們計算機上的任務管理器時,進程Tab頁上,咱們看到的就是進程;而獨立進程程序的子任務就是線程(不絕對,也能夠存在多進程的程序)。好比:QQ運行時(進程),就有不少子任務(線程)在同時運行:你即能一遍和基友視頻,一遍還能和其餘基友文字聊天這就體現了多線程,其中每一項子任務均可以理解爲線程。
MDove:對於咱們開發者來講線程是一個很常見的概念。對於Java後臺來講,可以熟練的掌握對多線程的使用。能夠說是掌握核心科技同樣。
小A:???聽你這麼說,多線程沒什麼難的呀?
MDove:初生牛犢不怕虎,但你要明白,虎終究是虎。多線程的一大難點在於線程安全問題。由於內存共享的緣由,致使了線程刷新內存的滯後性。
小A:???什麼意思???
MDove:打個比方,在Java線程模型中:每一個線程運行時,都會把主內存中的變量值複製到本身的工做內存當中,當本身執行完畢後,在把計算完畢的工做內存中的變量,反過來賦值給主內存。
小A:嗯?這好像沒什麼問題啊?
MDove:沒問題?問題大了去了!我們舉一個花錢的例子:如今我們帳本上有十個億。你是一個線程,我是一個線程。
此時我們的帳本還剩9個億。
此時我們的帳本還剩8個億。
小A:等會等會?你想啥呢?錢越花越多了!我都拿走1個億了,你那咋還9個億呢?你就不會同步一個個人帳本麼?
MDove:沒錯呀,我就不會同步一個你的帳本呀!這就是多線程的問題因此。由於每一個線程是獨立運行的,誰都無論誰,所以,如何同步線程之間的數據便成了相當重要的一點!
小A:這麼一說我就明白了,那怎麼同步呢?
MDove:其實剛纔的問題就出如今帳本的不一樣步上,所以若是咱們可以解決帳本的同步問題,理論上就能夠解決我們的線程安全問題。固然你能夠用一些手段通知我,讓我更新個人帳本(可見性)。可是仍存在問題,若是咱們寫帳本的操做是個多步驟的複雜操做,可能就會存在問題了,由於這個裏每一步通存在同步問題,只有當咱們的寫帳本操做是一個單一操做(原子性)那麼這種作法就是沒有問題的。
小A:侷限還挺多,那有沒有其餘方式呢?
MDove:接下來講一個加鎖的方式。舉個我們上廁所的例子。咱們不少人都要上廁所,若是咱們的廁所沒有任何措施,那麼畫面簡直沒法想象。所以,我們...那啥...大號...的時候,都會把門鎖上。其餘人一看門鎖上了,也就只好默默的憋一會。
MDove:當咱們解決後,打開門,其餘人就能夠盡情釋放了。
那麼這個過程就至關於:一個線程在操做一個變量時,直接把這個變量鎖起來。其餘線程只能等着,所以確定就不會存在多個線程同時操做變量的問題了。
小A:那麼接下來就是隊伍中第一我的去...那啥麼?
MDove:固然不是,線程的世界可沒有什麼先來後到。而是按線程的優先級去排列。那麼若是沒有優先級,那就看誰的拳頭更硬誰的運氣更好了。
小A:好殘暴,那有沒有順利排列的可能性呢?那咱們可不能夠本身固定一個順序去開啓線程的執行呢?
MDove:咱們固然能夠指定一種策略去順序的start咱們的線程,可是咱們只能保證線程start的順序,沒辦法保證線程調度的順序。由於對於線程來講,何時可以得到操做系統的寵幸那是不肯定的。所以線程會有多種狀態:
新建(NEW),表示線程被建立出來還沒真正啓動的狀態。
就緒(RUNNABLE),表示該線程已經在 JVM 中執行,固然因爲執行須要計算資源,它多是正在運行,也可能還在等待系統分配給它 CPU 片斷,在就緒隊列裏面排隊。
阻塞(BLOCKED),阻塞表示線程在等待鎖釋放。好比,線程試圖去獲取某個鎖,可是其餘線程已經獨佔了,那麼當前線程就會處於阻塞狀態。
等待(WAITING),表示正在等待其餘線程採起某些操做。。
終止(TERMINATED),不論是意外退出仍是正常執行結束,線程已經完成使命,終止運行。
固然也能夠加上一個:運行(RUNNING):可運行狀態(RUNNABLE)的線程得到了CPU時間片,開始執行代碼。
MDove:我們再回到那個廁所的例子。咱們平常中...廁所確定不止一個坑位,通常會有好幾個。畢竟都是解決一樣的問題,沒有隻設置一個坑位的道理。
MDove:因此對於咱們程序來講也是如此,在面對類型的場景也會有相似的實現,這個方式就叫作分段鎖。好比:ConcurrentHashMap,JDK1.8版本以前的設計。
MDove:固然關於鎖這個話題,其實水是很深的。咱們嘚吧嘚說了這麼多,其實就是在解決多線程安全問題。所以明白了吧,多線程是一個值得深刻學習的內容。
小A:學的我熱血沸騰的,接下來教教我,Java中對線程的使用吧!
MDove:別急,聊了這麼久廁所的話題,容我上個廁所,我們下期再來聊一聊線程的使用。