Java 線程入門知識總結

定義線程

  1. 定義一個實現 Runnable 接口的類 A, 並實現該接口中的 run 方法, 最後實例化類 A, 做爲 Thread 類的構造參數。
// 定義一個實現 Runnable 接口的類 A,  並實現該接口中的 run 方法
public class A implements Runnable {
    [@Override](https://my.oschina.net/u/1162528)
    public void run() {
        System.out.println("開啓一個縣城... ");
    }
}

// 實例化類 A
A task = new A();

// 做爲 Thread 類的構造參數。 
Thread t = new Thread(task);
  1. 定義一個繼承 Thread 類的類 A, 並重寫類 A 的 run 方法

注意: 其實仍是 Runnable 接口中 run 方法,由於 Thread 類實現了 Runnable接口java

// 定義一個繼承 Thread 類的類 A,  重寫類 A 的 run 方法
public class A extends Thread {
    [@Override](https://my.oschina.net/u/1162528)
    public void run() {
        System.out.println();
    }
}

Thread t = new Thread();

其餘:經過線程池 或者 實現Callable接口的方法。 暫時很少作介紹安全

經過實現 Runnable 接口與繼承 Thread 類定義線程的區別

  • Runnbale 接口的實現類必須重寫 run() 方法, 而 Thread類 的實現類有默認實現的run方法多線程

  • Runnbale 接口的實現類並非真正的線程類, 他只是執行線程的一個任務類jvm

  • Thread 類要想以線程的方式執行run方法,只能依靠Thread類ide

  • 繼承 Thread 類會形成單繼承的侷限性函數

線程的生命週期

線程的生命週期指的是從線程的建立到啓動直到結束。this

java 線程的 6 種狀態操作系統

注意: 這裏說的是 java 線程的狀態,並不是操做系統的線程狀態.net

Thread 類中經過枚舉定義了線程的狀態線程

public enum State {
   
    NEW,

    RUNNABLE,

    BLOCKED,

    WAITING,
  
    TIMED_WAITING,

    TERMINATED;
}
  • New:new Thread() 後線程的狀態就是新建。

  • Runnable:線程一旦調用 start() 方法,不管是否運行,狀態都爲 Runable, Runable 狀態指示表示線程能夠運行,不表示線程當下必定在運行,線程是否運行由虛擬機所在操做系統調度決定。

  • BLOCKED:線程試圖獲取一個內部對象的 Monitor(進入synchronized方法或synchronized塊)可是其餘線程已經搶先獲取,那此線程被阻塞,知道其餘線程釋放 Monitor 而且線程調度器容許當前線程獲取到 Monitor,此線程就恢復到可運行狀態。

  • WAITING:當一個線程等待另外一個線程通知調度器一個條件時,線程進入等待狀態。

  • TIMED_WAITING:和等待相似,某些形成等待的方法會容許傳入超時參數,這類方法會形成計時等待,收到其餘線程的通知或者超時都會恢復到可運行狀態。

  • TERMINATED:線程執行完畢正常結束或執行過程當中因未捕獲異常意外終止都會是線程進入被終止狀態

擴展

操做系統中線程的5中狀態

  • 新建
  • 就緒
  • 運行
  • 阻塞
  • 終止

線程調度

操做系統會給每一個線程分配時間片, 在某一時刻只執行一個時間片的線程。每一個java程序啓動後, jvm會自動幫咱們建立兩個線程, 一個是main, 一個是GC

線程調度的實現方式

  • 分時調度模型

    讓全部線程輪流得到CPU的控制權,而且爲每一個線程平均分配CPU時間片斷

  • 搶佔式調度模型

    選擇優先級相對較高的線程執行,若是全部線程的優先級相同,則隨機選擇一個線程執行 Java虛擬機採用此種調度模型。

java 線程分類

用戶線程

也稱非守護線程, jvm會在全部非守護線程結束後隨之離開

守護線程

也稱做後臺線程, 當進程中的全部 非後臺線程 結束後, 後臺線程也會隨之結束。

  • 如何設置後臺線程

    在線程啓動前調用setDaemon()方法

  • 爲何GC線程是守護線程?

    由於當全部的非守護線程結束後, 也就不會產生垃圾, 那麼GC線程也就沒有存在的意義

線程安全問題

出現線程不安全的條件

  1. 必須存在兩個或者兩個以上的線程。

  2. 多個線程共享着一個資源,並且操做資源的代碼有多句。

解決辦法

1. 同步代碼塊

使用 synchronized 修飾代碼塊, 以下所示

public  void methodA() {
    synchronized (this){
        // doSomething
    }
}

注意的事項:

  • 鎖對象能夠是任意的一個對象。
  • 鎖對象必須是多個線程共享 的資源。
  • 調用了sleep方法的線程並不會釋放鎖對象。
  • 若是不存在着線程安全問題,千萬不要使用同步代碼塊或者是同步函數, 由於會下降效率的。

2. 同步函數

使用synchronized修飾該函數則稱做爲同步函數, 以下所示。

public synchronized void methodA() {
    // doSomething        
}

注意的事項:

  • 非靜態同步函數的鎖對象是this對象,靜態函數的鎖對象是當前所屬類的class文件對象。
  • 同步函數的鎖對象是固定的,沒法更改。

推薦使用: 同步代碼塊

  1. 同步代碼塊的鎖對象能夠由咱們本身指定,同步函數的鎖對象是固定的。
  2. 同步代碼塊能夠隨意指定那個範圍須要被同步,而同步函數必須是整個函數都同步, 代碼不靈活。

死鎖

死鎖出現的條件

  • 必須存在兩個及兩個以上的線程
  • 這些線程共享兩個及兩個以上的資源
  • 多線程各自持有不一樣的鎖,並試圖獲取對方已持有的鎖

如何解決

線程安全問題解決後,會出現死鎖問題,死鎖問題沒法徹底解決,只能儘可能去避免死鎖出現的條件

相關文章
相關標籤/搜索