@Java | Thread & synchronized - [ 多線程 理論知識]

一. 線程狀態轉換圖

線程狀態轉換圖

線程間的狀態轉換說明:jvm

  1. 新建(new):新建立了一個線程對象。
  2. 可運行狀態(runnable):線程對象建立後,其餘線程(好比main線程)調用了該對象的start()方法。該狀態的線程位於可運行線程池中,等待被線程調度選中,獲取cpu的使用權 。
  3. 運行(running):可運行狀態(runnable)的線程得到了cpu時間片(timeslice) ,執行程序代碼。
  4. 阻塞狀態(blocked):阻塞狀態是指線程由於某種緣由放棄了cpu使用權,也即讓出了cpu timeslice,暫時中止運行。直到線程進入可運行(runnable)狀態,纔有機會再次得到cpu timeslice 轉到運行(running)狀態。阻塞的狀況分三種:spa

    • 等待阻塞:運行(running)的線程執行o.wait()方法,JVM會把該線程放入等待隊列(waitting queue)中(wait會釋放持有的鎖)。
    • 同步阻塞:運行(running)的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用,則JVM會把該線程放入鎖池(lock pool)中。
    • 其餘阻塞:運行(running)的線程執行Thread.sleep(long ms)t.join()方法,或者發出了I/O請求時,JVM會把該線程置爲阻塞狀態。當sleep()狀態超時join()等待線程終止或者超時或者I/O處理完畢時,線程從新轉入可運行(runnable)狀態(注意:sleep是不會釋放持有的鎖)。
  5. 死亡(dead):線程run()main()方法執行結束,或者因異常退出了run()方法,則該線程結束生命週期。死亡的線程不可再次復生。

二. 線程的調度

  1. 調整線程優先級:Java線程有優先級,優先級高的線程會得到較多的運行機會。
  2. 線程睡眠Thread.sleep(long millis)方法,使線程轉到阻塞狀態。millis參數設定睡眠的時間,以毫秒爲單位。當睡眠結束後,就轉爲就緒(Runnable)狀態。sleep()平臺移植性好。
  3. 線程等待Object類中的wait()方法,致使當前的線程等待,直到其餘線程調用此對象的 notify()方法或notifyAll()喚醒方法。這個兩個喚醒方法也是Object類中的方法,行爲等價於調用 wait(0)
  4. 線程讓步Thread.yield()方法,暫停當前正在執行的線程對象,把執行機會讓給相同或者更高優先級的線程。
  5. 線程加入join()方法,等待其餘線程終止。在當前線程中調用另外一個線程join()方法,則當前線程轉入阻塞狀態,直到另外一個進程運行結束,當前線程再由阻塞轉爲就緒狀態。
  6. 線程喚醒Object類中的notify()方法,喚醒在此對象監視器上等待的單個線程。若是全部線程都在此對象上等待,則會選擇喚醒其中一個線程。選擇是任意性的,並在對實現作出決定時發生。線程經過調用其中一個wait方法,在對象的監視器上等待。直到當前的線程放棄此對象上的鎖定,才能繼續執行被喚醒的線程。被喚醒的線程將以常規方式與在該對象上主動同步的其餘全部線程進行競爭;例如,喚醒的線程在做爲鎖定此對象的下一個線程方面沒有可靠的特權或劣勢。相似的方法還有一個notifyAll(),喚醒在此對象監視器上等待的全部線程。
注意:Thread中suspend()和resume()兩個方法在JDK1.5中已經廢除,再也不介紹。由於有死鎖傾向。

三. 常見線程名詞解釋

  1. 主線程JVM調用程序main()所產生的線程。
  2. 當前線程:這個是容易混淆的概念。通常指經過Thread.currentThread()來獲取的進程。
  3. 後臺線程:指爲其餘線程提供服務的線程,也稱爲守護線程。JVM的垃圾回收線程就是一個後臺線程。用戶線程和守護線程的區別在於,守護線程等待用戶線程結束而結束
  4. 前臺線程:是指接受後臺線程服務的線程,其實前臺後臺線程是聯繫在一塊兒,就像傀儡和幕後操縱者同樣的關係。傀儡是前臺線程、幕後操縱者是後臺線程。由前臺線程建立的線程默認也是前臺線程。能夠經過isDaemon()setDaemon()方法來判斷和設置一個線程是否爲後臺線程

線程類的一些經常使用方法:線程

  • sleep(): 強迫一個線程睡眠N毫秒。
  • isAlive(): 判斷一個線程是否存活。
  • join(): 等待線程終止。
  • activeCount(): 程序中活躍的線程數。
  • enumerate(): 枚舉程序中的線程。
  • currentThread(): 獲得當前線程。
  • isDaemon(): 一個線程是否爲守護線程。
  • setDaemon(): 設置一個線程爲守護線程。
  • setName(): 爲線程設置一個名稱。
  • wait(): 強迫一個線程等待。
  • notify(): 通知一個線程繼續運行。
  • setPriority(): 設置一個線程的優先級。

四. 關於main線程

  1. JVM會在全部的非守護線程(用戶線程)執行完畢後退出;
  2. main線程是用戶線程
  3. 僅有main線程一個用戶線程執行完畢,不能決定JVM是否退出,也便是說main線程並不必定是最後一個退出的線程。
經過 jstack咱們能夠把 jvm當前的線程狀態 dump下來進行分析驗證
或者經過JMX的API進行線程信息的輸出,代碼以下:
public class ThreadNumDemo {
    public static void main(String[] args) {
        ThreadMXBean threadMXBean =ManagementFactory.getThreadMXBean();
        ThreadInfo[] threadInfos=threadMXBean.dumpAllThreads(false,false);
        for (ThreadInfo threadInfo : threadInfos) {
            System.out.println(threadInfo.getThreadId()+"-"+threadInfo.getThreadName());
        }
    }
}
相關文章
相關標籤/搜索