Java併發程式設計:Java執行緒

xylitolz發表於2020-11-15

建立和執行執行緒

  • 方法一:直接使用Thread
// 建立執行緒物件
Thread t = new Thread("name") {
    public void run() {
        // 要執行的任務
    }
};
// 啟動執行緒
t.start();

// Java 8 以後可以使用lambda精簡程式碼
Thread t = new Thread(()->{
    // 要執行的程式碼
});
  • 方法二:使用Runnable配合Thread

把【執行緒】與【任務】(要執行的程式碼)分開,Thread代表執行緒,Runnable可執行的任務(執行緒要執行的程式碼)

Runnable runnable = new Runnable() {
    public void run() {
        // 要執行的任務
    }
}; 
// 建立執行緒物件 引數1:任務物件 引數2:執行緒名字
Thread t = new Thread(runnable, "name");
// 啟動執行緒
t.start();
  • 小結
    • 方法一把執行緒和任務合併在了一起,方法二是把執行緒和任務分開了
    • 用Runnable更容易與執行緒池等高階API配合
    • 用Runnable讓任務類脫離了Thread繼承體系,更靈活
  • 方法三:FutureTask配合Thread
// 建立任務物件
FutureTask<Integer> task3 = new FutureTask<>(()->{
    log.debug("hello");
    return 100;
});
// 引數1 是任務物件; 引數2 是執行緒名字,推薦
new Thread(task3, "t3").start();
// 主執行緒阻塞,同步等待 task 執行完畢的結果
Integer result = task3.get();
log.debug("結果是:{}", result);

原理之執行緒執行

棧與棧幀

JVM中由堆、棧、方法區所組成,其中棧記憶體給執行緒用,每個執行緒啟動後,虛擬機器就會為其分配一塊棧記憶體。

  • 每個棧由多個棧幀(Frame)組成,對應著每次方法呼叫時所佔用的記憶體
  • 每個執行緒只能有一個活動棧幀,對應著當前正在執行的那個方法

執行緒上下文切換

因為以下一些原因導致CPU不再執行當前的執行緒,轉而執行另一個執行緒的程式碼:

  • 被動
    • 執行緒的CPU時間片用完
    • 垃圾回收
    • 有更高優先順序的執行緒需要執行
  • 主動
    • 執行緒自己呼叫了sleep、yield、wait、join、park、synchronized、lock等方法

當Context Switch發生時,需要由作業系統儲存當前執行緒的狀態,並恢復另一個執行緒的狀態,Java中對應的概念就是程式計數器(Program Counter Register), 它的作用是記住下一條jvm指令的執行地址,是執行緒私有的

  • 狀態包括程式計數器、虛擬機器棧中每個棧幀的資訊,如區域性變數、運算元棧、返回地址等
  • Context Switch頻繁發生會影響效能

常見方法

方法名static功能說明注意
start()啟動一個新執行緒,在新的執行緒執行 run 方法中的程式碼start 方法只是讓執行緒進入就緒,裡面程式碼不一定立刻執行(CPU 的時間片還沒分給它)。每個執行緒物件的start方法只能呼叫一次,如果呼叫了多次會出現IllegalThreadStateException
run()新執行緒啟動後會呼叫的方法如果在構造 Thread 物件時傳遞了 Runnable 引數,則執行緒啟動後會呼叫 Runnable 中的 run 方法,否則預設不執行任何操作。但可以建立 Thread 的子類物件,來覆蓋預設行為
join()等待執行緒執行結束
join(long n )等待執行緒執行結束,最多等待 n毫秒
getId()獲取執行緒長整型的 idid唯一
getName()獲取執行緒名
setName(String)修改執行緒名
getPriority()獲取執行緒優先順序
setPriority(int)修改執行緒優先順序java中規定執行緒優先順序是1~10 的整數,較大的優先順序能提高該執行緒被 CPU 排程的機率
getState()獲取執行緒狀態Java 中執行緒狀態是用 6 個 enum 表示,分別為:NEW, RUNNABLE, BLOCKED, WAITING,TIMED_WAITING, TERMINATED
isInterrupted()判斷是否被打斷不會清除打斷標記
isAlive()執行緒是否存活(還沒有執行完畢)
interrupt()打斷執行緒如果被打斷執行緒正在 sleep,wait,join 會導致被打斷的執行緒丟擲 InterruptedException,並清除 打斷標記 ;如果打斷的正在執行的執行緒,則會設定 打斷標記 ;park 的執行緒被打斷,也會設定 打斷標記
interrupted()static判斷當前執行緒是否被打斷會清除 打斷標記
currentThread()static獲取當前正在執行的執行緒
sleep(long n)static讓當前執行的執行緒休眠n毫秒,休眠時讓出 cpu的時間片給其它執行緒
yield()static提示執行緒排程器讓出當前執行緒對CPU的使用主要是為了測試和除錯

Reference

全面深入學習java併發程式設計

相關文章