[短文速讀 -5] 多線程編程引子:進程、線程、線程安全

前言

最近在總結《Java多線程編程核心技術》這本書。實話實說:多線程編程核心技術,這些字眼屬實有些誇大。面試

可是也不能由於此,就直接否定了書籍自己的價值。這是一篇比較適合入門閱讀的書籍。和我最近在嘗試寫的文章有類似之處,也就是盡力讓知識點,少思考性而多閱讀性。編程

所以接下來會將這本書的內容,揉到個人接下來的文章中,旨在:真正能在碎片化時代下,進行有效學習。安全

愛因斯坦:「若是你不能簡單地解釋同樣東西,說明你沒真正理解它。」多線程

[短文速讀-1] a=a+b和a+=b的區別併發

[短文速讀-2] 重載/重寫,動/靜態分派?(從新修訂)工具

[短文速讀-3] 內部匿名類使用外部變量爲何要加finalpost

[短文速度-4] new子類是否會實例化父類性能

[短文速讀 -5] 多線程編程引子:進程、線程、線程安全學習

正文

毫無疑問,一切的開始。確定是先介紹介紹概念性的東西。主題是線程,可是談到線程,勢必不能忘了進程。所以讓咱們先來聊一聊線程和進程的概念。操作系統

接下來讓咱們有請文章一向的主角:小AMDove出場~

進程和線程

小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:沒問題?問題大了去了!我們舉一個花錢的例子:如今我們帳本上有十個億。你是一個線程,我是一個線程。

  • 我先執行了,我拿了一個億,去建設了一下社會主義核心價值觀,而後我在個人帳本里記了一下帳:我拿了1個億,手頭還有9個億

此時我們的帳本還剩9個億

  • 接下來,你也出動了,你拿了9個億中的一個億,你也在你的帳本里記了一下帳:我拿了1個億,還有8個億。而後你去吸菸喝酒燙頭了。

此時我們的帳本還剩8個億

  • 這個時候我幹完了個人事,我花了5千萬,還剩5千萬。而後對於我來講個人帳本變成了,還有9億5千萬。此時我把個人帳本寫到了我們們公共帳本里...

小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:別急,聊了這麼久廁所的話題,容我上個廁所,我們下期再來聊一聊線程的使用。

劇終

我是一個應屆生,最近和朋友們維護了一個公衆號,內容是咱們在從應屆生過渡到開發這一路所踩過的坑,以及咱們一步步學習的記錄,若是感興趣的朋友能夠關注一下,一同加油~

我的公衆號:IT面試填坑小分隊
相關文章
相關標籤/搜索