並行一(基本概念及理論準備)

2020-10-23 12:00:33

寫在前面:

多執行緒並行等知識點涉及面廣,延伸度大,理論加原始碼的方式整理關於執行緒的部分基礎知識,其他更多的更深的知識會在後面一一學習和整理,先學習基礎,再延伸。

 

目錄

一、執行緒與程序

二、執行緒實現

繼承 Thread

實現Runnable

實現Callable&Future

三、執行緒生命週期及狀態轉換

新建

可執行

執行

阻塞

等待

超時等待

終止           

 

四、常見操作方法分析

Thread.sleep(long millis)

Thread.yield()

t.join()/t.join(long millis)

obj.wait()

obj.notify()

五、執行緒池

六、常見並行容器

ConcurrentHashMap

其他並行容器

佇列

七、執行緒安全



一、執行緒與程序

程序是指一個記憶體中執行的應用程式,每個程序都有自己獨立的一塊記憶體空間,是系統進行資源分配和排程的一個獨立單位,是程式執行的最小單元。

執行緒是指程序中的一個執行流程,沒有自己的記憶體空間,是cpu執行和分派的最小單元。

在Java中,每次程式執行至少啟動2個執行緒:一個是main執行緒,一個是垃圾收集執行緒。因為每當使用java命令執行一個類的時候,實際上都會啟動一個JVM,每一個JVM實際上就是在作業系統中啟動了一個程序。

 

二、執行緒實現

繼承 Thread

由於java是單繼承,所以基本不用這種實現方式

實現Runnable

介面,重寫run()

實現Callable&Future

待續

三、執行緒生命週期及狀態轉換

新建

new                【來到體育場 】

可執行

runnable         【進入備跑區】

執行緒物件建立後,其他執行緒呼叫了該執行緒的start方法,進入執行緒池等待被排程選中,獲取cpu使用權。當前執行緒sleep()方法結束,其他執行緒join()結束,等待使用者輸入完畢,某個執行緒拿到物件鎖,這些執行緒也將進入可執行狀態。當前執行緒時間片用完了,呼叫當前執行緒的yield()方法,當前執行緒進入可執行狀態。鎖池裡的執行緒拿到物件鎖後,進入可執行狀態。

執行

running           【起跑】 

runnable狀態下獲得了cpu時間片(timeslice),執行程式。

阻塞

blocked           【停下去做點啥】     

執行緒因為某些原因放棄了cpu使用權,讓出了cpu timeslice,暫停執行。直到執行緒重新進入runnable。

所謂阻塞狀態是正在執行的執行緒沒有執行結束,暫時讓出CPU,這時其他處於就緒狀態的執行緒就可以獲得CPU時間,進入執行狀態。

blocked分三種:
等待阻塞 wait()方法執行,進入等待佇列(waitting queue)
同步阻塞 running的執行緒在獲取物件的同步鎖時,若該同步鎖被別的執行緒佔用,JVM會把它放到鎖池(lock pool)中,等拿到鎖之後才會進入可執行
其他阻塞 Thread.sleep(long ms)                                               睡上五分鐘,醒來再進執行緒池
                t.join()                                                                        跑著跑著突然被插隊,你不得不停下
               發出IO請求時,jvm會把該執行緒置為阻塞狀態。         跑著跑著,你去看了看檔案,所以得停下
當           sleep()狀態超時                                                          睡醒了
               join()等待執行緒終止或者超時                                       插隊的人走了或掛了
               或者I/O處理完畢時                                                     檔案看完了

執行緒重新轉入可執行(runnable)狀態。

等待

waiting             【等著,別人叫再跑】

處於這種狀態的執行緒不會被分配CPU執行時間,它們要等待被顯式地喚醒,否則會處於無限期等待的狀態。

超時等待

time waiting     【等著,過了等待時間就不等了】

處於這種狀態的執行緒不會被分配CPU執行時間,不過無須無限期等待被其他執行緒顯示地喚醒,在達到一定時間後它們會自動喚醒。

終止           

terminated       【跑完或者意外退場】

run()、main()執行結束,或因異常退出run()方法,結束該執行緒生命週期,死亡的不可復生。

 

四、常見操作方法分析

Thread.sleep(long millis)

一定是當前執行緒呼叫此方法,當前執行緒進入阻塞,但不釋放物件鎖,millis後執行緒自動甦醒進入可執行狀態。作用:給其它執行緒執行機會的最佳方式。

Thread.yield()

一定是當前執行緒呼叫此方法,當前執行緒放棄獲取的cpu時間片,由執行狀態變會可執行狀態,讓OS再次選擇執行緒。作用:讓相同優先順序的執行緒輪流執行,但並不保證一定會輪流執行。實際中無法保證yield()達到讓步目的,因為讓步的執行緒還有可能被執行緒排程程式再次選中。Thread.yield()不會導致阻塞。

t.join()/t.join(long millis)

當前執行緒裡呼叫其它執行緒1的join方法,當前執行緒阻塞,但不釋放物件鎖,直到執行緒1執行完畢或者millis時間到,當前執行緒進入可執行狀態。

obj.wait()

當前執行緒呼叫物件的wait()方法,當前執行緒釋放物件鎖,進入等待佇列。依靠notify()/notifyAll()喚醒或者wait(long timeout)timeout時間到自動喚醒。

obj.notify()

喚醒在此物件監視器上等待的單個執行緒,選擇是任意性的。notifyAll()喚醒在此物件監視器上等待的所有執行緒。
 

五、執行緒池

ThreadPoolExecutor extends Executor

六、常見並行容器

ConcurrentHashMap

待續

其他並行容器

待續

佇列

同步佇列

當前執行緒想呼叫物件A的同步方法時,發現物件A的鎖被別的執行緒佔有,此時當前執行緒進入同步佇列。簡言之,同步佇列裡面放的都是想爭奪物件鎖的執行緒。同步佇列是在同步的環境下才有的概念,一個物件對應一個同步佇列。

鎖池佇列

鎖池裡面放的都是想爭奪物件鎖的執行緒。當一個執行緒1被另外一個執行緒2喚醒時,1執行緒進入鎖池狀態,去爭奪物件鎖。

鎖池是在同步的環境下才有的概念,一個物件對應一個鎖池。

等待佇列

        待續

七、執行緒安全

定義:CPU的使用權搶佔和資源的共用發生了衝突