寫在前面:
多執行緒並行等知識點涉及面廣,延伸度大,理論加原始碼的方式整理關於執行緒的部分基礎知識,其他更多的更深的知識會在後面一一學習和整理,先學習基礎,再延伸。
目錄
程序是指一個記憶體中執行的應用程式,每個程序都有自己獨立的一塊記憶體空間,是系統進行資源分配和排程的一個獨立單位,是程式執行的最小單元。
執行緒是指程序中的一個執行流程,沒有自己的記憶體空間,是cpu執行和分派的最小單元。
在Java中,每次程式執行至少啟動2個執行緒:一個是main執行緒,一個是垃圾收集執行緒。因為每當使用java命令執行一個類的時候,實際上都會啟動一個JVM,每一個JVM實際上就是在作業系統中啟動了一個程序。
由於java是單繼承,所以基本不用這種實現方式
介面,重寫run()
待續
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()方法,結束該執行緒生命週期,死亡的不可復生。
一定是當前執行緒呼叫此方法,當前執行緒進入阻塞,但不釋放物件鎖,millis後執行緒自動甦醒進入可執行狀態。作用:給其它執行緒執行機會的最佳方式。
一定是當前執行緒呼叫此方法,當前執行緒放棄獲取的cpu時間片,由執行狀態變會可執行狀態,讓OS再次選擇執行緒。作用:讓相同優先順序的執行緒輪流執行,但並不保證一定會輪流執行。實際中無法保證yield()達到讓步目的,因為讓步的執行緒還有可能被執行緒排程程式再次選中。Thread.yield()不會導致阻塞。
當前執行緒裡呼叫其它執行緒1的join方法,當前執行緒阻塞,但不釋放物件鎖,直到執行緒1執行完畢或者millis時間到,當前執行緒進入可執行狀態。
當前執行緒呼叫物件的wait()方法,當前執行緒釋放物件鎖,進入等待佇列。依靠notify()/notifyAll()喚醒或者wait(long timeout)timeout時間到自動喚醒。
喚醒在此物件監視器上等待的單個執行緒,選擇是任意性的。notifyAll()喚醒在此物件監視器上等待的所有執行緒。
ThreadPoolExecutor extends Executor
待續
待續
同步佇列
當前執行緒想呼叫物件A的同步方法時,發現物件A的鎖被別的執行緒佔有,此時當前執行緒進入同步佇列。簡言之,同步佇列裡面放的都是想爭奪物件鎖的執行緒。同步佇列是在同步的環境下才有的概念,一個物件對應一個同步佇列。
鎖池佇列
鎖池裡面放的都是想爭奪物件鎖的執行緒。當一個執行緒1被另外一個執行緒2喚醒時,1執行緒進入鎖池狀態,去爭奪物件鎖。
鎖池是在同步的環境下才有的概念,一個物件對應一個鎖池。
等待佇列
待續
定義:CPU的使用權搶佔和資源的共用發生了衝突