多執行緒_基礎
阿新 • • 發佈:2022-02-05
一.一個Java程式最少開幾個執行緒?
- 3個:主執行緒;gc執行緒;異常處理執行緒
二.執行緒的生命週期以及狀態?
阻塞的分類:
- 等待阻塞:執行wait(),需要notify()/notifyAll()喚醒
- 同步阻塞:等待拿到鎖
- 其他阻塞:執行sleep(),join(),或者發出I/O請求。都會進入阻塞
三.建立執行緒的幾種方式?
建立執行緒:
- 建立一個Thread物件。new Thread().start;
- 使用執行緒池 Executors.newFixedThreadPool(10); //建立執行緒池
定義執行緒做的事
- 繼承Thread類,重寫run()
- 需要建立一個子類
- 需要建立一個子類
- 實現Runnable介面,重寫run()
- 打破單繼承的侷限,可以在實現介面的時候繼承自己的父類。
- 可以使用lambda代替 ()->{}
- 實現Callable介面,重寫call()
- 有返回值,有異常
- 需要用一個過度類FutureTask,可以使用該類的get()獲取返回值
四.sleep,wait,yield,join的區別
sleep(),wait()的區別?
- 所屬的類不同:sleep來自Thread類,wait來自Object類
- 有沒有釋放鎖(釋放資源)
- sleep:不釋放 wait:釋放,進入等待池中(主要就是為了執行緒的通訊)
- sleep:不釋放 wait:釋放,進入等待池中(主要就是為了執行緒的通訊)
- 使用的範圍不同
- sleep:任何地方 wait:必須使用在同步程式碼塊/同步方法中
- sleep:任何地方 wait:必須使用在同步程式碼塊/同步方法中
- 是否有異常
- sleep:有,需要捕獲 wait:沒有
- sleep:有,需要捕獲 wait:沒有
補充:解釋上面出現的名詞
- 鎖池:需要競爭同步鎖的執行緒都先放在鎖池中,鎖一旦釋放,鎖池中的執行緒開始搶鎖
- 等待池:當執行緒執行wait(),就會進入等待池中。執行notify()/notifyAll()就會將等待池中的執行緒放到鎖池中(也就是喚醒)
yield和join
- yield():執行緒讓步
- 暫停當前正在執行的執行緒物件,並執行其它執行緒。不進入阻塞
- 當前執行緒交出cpu許可權,讓cpu執行其他執行緒(但是CPU可能重新分配時,再次執行該執行緒)
- join():執行緒插入
- 線上程a中呼叫執行緒b的join(),此時執行緒a進入阻塞狀態,直到執行緒b完全執行完以後,執行緒a才結束阻塞狀態。
五.其他一些小問題
怎麼理解執行緒安全問題?
- 多個執行緒操作共享資料時,就會產生執行緒安全問題
- 造成這個問題的本質就是堆空間是執行緒共享的
併發,並行,序列的區別?
- 序列:執行完一個程式再執行下一個程式
- 並行:多個事情,在一個時間點內發生。經常是對於多核cpu
- 併發:多個事情,在一個時間段內發生。在這個時間段中cpu快速切換,感覺像一起執行
- 併發程式設計的本質:充分利用CUP的資源
守護執行緒?
java中兩種執行緒:守護執行緒(後臺執行緒) 非守護執行緒(使用者執行緒)
- 守護執行緒是專門給所有的使用者執行緒(非守護執行緒)提供服務的執行緒,不是專門給一個執行緒提供服務
- gc垃圾回收執行緒就是典型的守護執行緒,當JVM中沒有任何的使用者執行緒執行,守護執行緒就會自動的斷開
- 使用守護執行緒中產生的執行緒也是守護執行緒
- 不要把I/O,file操作交給守護執行緒,因為它隨時可能中斷(沒有使用者執行緒執行的時候)
- 對於執行緒池Executors,就算你把它設定為守護執行緒,也會變為非守護執行緒
- 使用thread.setDaemon(true);//將執行緒設定為守護執行緒
執行緒終止的幾種方式?
- 正常執行結束
- 使用退出標誌退出執行緒(將run()的所有內容放在while(flag)中)
- Interrupt()方法結束執行緒 while (!isInterrupted()){..Thread.sleep().} 推薦
- Interrupt():如果執行緒處於阻塞狀態,終止阻塞。丟擲異常。然後在異常處理中break;
- stop()方法結束執行緒 不推薦
- 強制終止執行緒,釋放該執行緒的所有的鎖。這樣做就會導致鎖釋放,造成執行緒不安全。
執行緒是否越多越好? 不一定,執行緒多了上下文切換就多了
- 對於計算的程式,執行緒數等於cpu核數最好
- 對於i/o程式,執行緒數等於i/o任務數最好
寄語:把努力當成你的一種習慣,而不是一時熱血