同步和非同步
同步就好比打電話,通訊雙方,你一句我一句,一句話得不到迴應就會一直問:“喂?喂?可以聽到麼?是不是訊號不好呀”。
非同步就像發簡訊,發完簡訊我就去幹點別的,看個視訊、玩個遊戲、幹啥都行,等對方給我回資訊了我再來處理簡訊(也可以不處理)。
執行緒和程式
程式的概念聽起來很抽象,不大好理解。但是我知道你肯定認識這個東西,請看下圖:
上方這些佔用我的電腦CPU、記憶體、磁碟、網路的這些就都是程式。
那什麼是執行緒呢?執行緒可以理解成是在程式中獨立執行的子任務。比如微信執行時就會有很多的子任務在同時執行。比如,視訊執行緒、下載執行緒、表情執行緒、語言執行緒等。簡單來說,一組執行緒互相協作完成某一個程式的一些功能供我們使用。
併發和並行
併發和並行乍一看好像是一種東西,但是實際上區別很大。並發表示的是交替做不同事情的能力,而並行表示的是同時做不同事情的能力。例如你吃飯吃到一半,電話來了,你停了下來接了電話,接完後繼續吃飯,這就是併發。你吃飯吃到一半,電話來了,你一邊打電話一邊吃飯,這是並行。
我們常說的高併發系統就是說的併發而不是並行。
並不是所有的系統都可以實現並行,因為一個CPU一次只能執行一條指令,所以想要實現並行必須是多核才可以
臨界資源
臨界資源:是一次僅允許一個程式使用的共享資源。例如公共電話,一次只能一個人使用
臨界區:每個程式中訪問臨界資源的那段程式碼叫做臨界區。例如使用公共電話的人
阻塞
執行緒在試圖執行程式碼前,會試圖獲取臨界區的鎖,如果得不到,執行緒就會被掛起等待,從而形成阻塞。
死鎖
多個執行緒迴圈等待它方佔有的資源而無限期地僵持下去的局面。例如兩個人想要使用公共電話打電話,結果一個人搶到了話筒,一個人撥了號。兩個人誰也不讓誰,就會無休止地等下去從而引起死鎖。
死鎖產生的四大必要因素:
互斥:某種資源一次只允許一個程式訪問,即該資源一旦分配給某個程式,其他程式就不能再訪問,直到該程式訪問結束。
佔有且等待:一個程式本身佔有部分資源,同時還有資源未得到滿足,正在等待其他程式釋放該資源。
不可搶佔:別人已經佔有了某項資源,你不能因為自己也需要該資源,就去把別人的資源搶過來。
迴圈等待:存在一個程式鏈,使得每個程式都佔有下一個程式所需的至少一種資源。
當以上四個條件都滿足時才會發生死鎖,所以想要避免死鎖只要能破壞上方四個條件的任意一個都可以。
飢餓
執行緒因為優先順序或其他原因始終無法獲取到臨界資源。例如A在使用公用電話在打電話,B來了之後在後面排隊。之後C來了,一看認識A,好麼,哥們你打完我來。然後D來了,他認識C。。。就這樣B一直等待從而引起飢餓。
活鎖
多個相互協作的執行緒為了彼此間的響應而相互禮讓,使得沒有一個執行緒能夠繼續前進,那麼就發生了活鎖。例如兩個人在一個很宅的衚衕裡。一次只能並排過兩個人。兩人比較禮貌,都要給對方讓路。 結果一起要麼讓到左邊,要麼讓到右邊,結果仍然是誰也過不去從而引起的活鎖。
執行緒的併發級別
阻塞:參見上方阻塞的定義
無飢餓:對比上方的飢餓,如果設定所有執行緒的優先順序相同,則任何想要獲取資源的執行緒都要排隊,那麼所有的執行緒都有機會執行。
無阻塞:所有執行緒一起修改臨界資源,修改完成後讀取該資源是否被其他執行緒修改,如被其他執行緒修改則進行回滾,然後進行重試。
無鎖:前面說的無阻塞是指所有的執行緒都能進入臨界區,但如果發生了競爭,執行緒發現自己的資料每次去操作總是跟其它執行緒產生衝突,它就會不停地重試,如果在臨界區當中有10個執行緒,執行緒1修改了部分資料,結果它被執行緒2干擾了,執行緒2又被執行緒3干擾,依此類推,最後執行緒1它又可能去干擾執行緒10,如果它們之間是彼此干擾的,最終會導致所有的執行緒都卡死在裡面。而無鎖在無阻塞的基礎上加一個了約束,保證在競爭當中有一個執行緒是必然能夠勝出的,這樣就能保證在臨界區的執行緒當中至少有一個是能順利走出去的。當第一個執行緒走出去之後,就有第二個執行緒、第三個執行緒、等所有的執行緒都能走出去
無等待:無等待相比於無鎖更進一步,它保證所有執行緒能進並且至少有一個執行緒能出來的同時還要求所有進入臨界區的執行緒都能夠在有限步當中完成其操作。