1:繼承Thread類創建線程
現象:創建線程的第一種方式,繼承Thread,重寫run方法,如果直接調用run方法,則和調用普通方法一樣,不會創建線程
結果顯示是 main線程調用
如果調用start,是 Thread-0 調用
調用run方法,很簡單,MyThread類繼承Thread,重寫了run,所以調用run實際調用的是子類MyThread類的run,
我們來看一下start方法
大致意思是:
start這個方法觸發這個線程開始執行,jvm會調用這個線程的run方法。
導致這兩個線程並發執行:當前線程調用完start就就結束了,另一個線程要執行run方法。
啟動這個線程超過1次是不合法的,尤其是線程已經執行完成不能再次被重啟。
我們通過注釋可以看出只有調用start方法才會創建線程,而且是准備就緒,沒有執行,具體執行需要
cpu分配時間片給該線程,這個線程只能被啟動一次,start方法上面有個synchronized鎖,應該就是控制多次啟動的。
多次啟動,會報非法狀態
來看一下start方法:
首先是判斷線程狀態,0為New新建,不是則拋異常,如果是則放入線程組,然后調用
start0方法啟動,創建該線程,創建過程設置開關,如果創建失敗則從線程組刪除
這個start0方法是jvm提供的方法,應該就是為線程開辟內存,分配資源等工作,具體怎么cpu怎么調到run方法的
還不知道,后面研究后 在補充 ?????????
來看一下run方法
如果這個thread構建的時候以一個runnable對象作為參數,那么啟動的時候,將會調用,否則不會被調用,
當然Thread的子類應該重寫這個方法
當繼承Thread時,已經重寫run方法,所以jvm底層調用run時,其實直接調用子類的方法,而不是該方法。
2:實現runnable的方式創建線程
來看一下構造Thread這個方法
new Thread(runnable);
到最后把入參的target賦值給了內部維護的target變量,
所以當調用start后,創建一個線程就緒狀態,等待分配時間片。
再來看一下Thread類的run方法:
因為沒有被重寫,所以會調用Thread類的run方法,target就是入參傳進來的MyRunnable對象,所以
會調用重寫的run方法。
3: 線程池方式創建線程
先來看一下創建線程池對象:
ExecutorService executors = Executors.newSingleThreadExecutor();
將創建的線程池對象委托給了
FinalizableDelegatedExecutorService 對象,
在這個
DelegatedExecutorService類里面,將入參委托給了ExecutorService來維護。
在回過頭來看線程池的execute方法:
然后調用到ThreadPoolExecutor方法
由於線程池里面的參數比較多,我們就假設線程池工作的線程數小於核心數:
先重點關注一下線程池的執行邏輯,具體線程池的細節可以在線程池一節在重點分析:
看一下new Worker(firstTask) 方法:
將runnable賦值給worker類中的變量,然后使用線程工廠創建一個線程,同時將當前worker對象作為參數傳進了線程中。
因為Worker類也實現了Runnable接口
由於我們創建線程時使用的是默認線程工廠:
所以看一下newThread的邏輯
將worker作為入參傳了進去,然后維護在Thread類中的target變量上。
當把worker對象放到集合workers中,添加成功后,會調用線程的start方法。
調用start方法,當cpu分配時間片給Thread時,就觸發了Worker對象的run方法
調用runWorker方法,就會調用MyRunnable方法的run方法,
就會調用我們自己實現的MyRunnable方法中。