1. 程式人生 > 其它 >多執行緒_基礎

多執行緒_基礎

一.一個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:沒有

補充:解釋上面出現的名詞

  • 鎖池:需要競爭同步鎖的執行緒都先放在鎖池中,鎖一旦釋放,鎖池中的執行緒開始搶鎖
  • 等待池:當執行緒執行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);//將執行緒設定為守護執行緒

執行緒終止的幾種方式?

  1. 正常執行結束
  2. 使用退出標誌退出執行緒(將run()的所有內容放在while(flag)中)
  3. Interrupt()方法結束執行緒 while (!isInterrupted()){..Thread.sleep().} 推薦
    • Interrupt():如果執行緒處於阻塞狀態,終止阻塞。丟擲異常。然後在異常處理中break;
  4. stop()方法結束執行緒 不推薦
    • 強制終止執行緒,釋放該執行緒的所有的鎖。這樣做就會導致鎖釋放,造成執行緒不安全。

執行緒是否越多越好? 不一定,執行緒多了上下文切換就多了

  • 對於計算的程式,執行緒數等於cpu核數最好
  • 對於i/o程式,執行緒數等於i/o任務數最好

寄語:把努力當成你的一種習慣,而不是一時熱血