1. 程式人生 > 其它 >【併發程式設計】java執行緒

【併發程式設計】java執行緒

一。建立執行緒的方式

  1.繼承Thread,直接執行

// 構造方法的引數是給執行緒指定名字,推薦
Thread t1 = new Thread("t1") {
 @Override
 // run 方法內實現了要執行的任務
 public void run() {
 log.debug("hello");
 }
};
t1.start();

  2.實現runnable,配合Thread

// 建立任務物件
Runnable task2 = new Runnable() {
 @Override
 public void run() {
 log.debug("hello");
 }
};
// 引數1 是任務物件; 引數2 是執行緒名字,推薦
Thread t2 = new Thread(task2, "t2"); t2.start();

  3.futureTask配合Thread,其中futuretask可以接受callable,可以返回執行緒的結果

// 建立任務物件
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);

二。檢視執行緒程序的方法

  1.windows系統下

    工作管理員可以檢視程序和執行緒數,也可以用來殺死程序

    tasklist 檢視程序

    taskkill 殺死程序

  2.linux系統下

    ps -fe 檢視所有程序

    ps -fT -p 檢視某個程序(PID)的所有執行緒

    kill 殺死程序

    top 按大寫 H 切換是否顯示執行緒

    top -H -p 檢視某個程序(PID)的所有執行緒 

  3.java

    jps 命令檢視所有 Java 程序

    jstack 檢視某個 Java 程序(PID)的所有執行緒狀態

    jconsole 來檢視某個 Java 程序中執行緒的執行情況(圖形介面) 

三。執行緒常見方法

方法名 static 功能說明 注意
start()   啟動一個新線 程,在新的執行緒 執行 run 方法 中的程式碼 start 方法只是讓執行緒進入就緒,裡面程式碼不一定立刻 執行(CPU 的時間片還沒分給它)。每個執行緒物件的 start方法只能呼叫一次,如果呼叫了多次會出現 IllegalThreadStateException
run()   新執行緒啟動後會 呼叫的方法 如果在構造 Thread 物件時傳遞了 Runnable 引數,則 執行緒啟動後會呼叫 Runnable 中的 run 方法,否則默 認不執行任何操作。但可以建立 Thread 的子類物件, 來覆蓋預設行為
join()   等待執行緒執行結 束  
join(long n)   等待執行緒執行結 束,最多等待 n 毫秒  
getId()   獲取執行緒長整型 的 id id 唯一
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的使用 主要是為了測試和除錯

四。sleep和yield的區別

  sleep

    1. 呼叫 sleep 會讓當前執行緒從 Running 進入 Timed Waiting 狀態(阻塞)

    2. 其它執行緒可以使用 interrupt 方法打斷正在睡眠的執行緒,這時 sleep 方法會丟擲 InterruptedException

    3. 睡眠結束後的執行緒未必會立刻得到執行

    4. 建議用 TimeUnit 的 sleep 代替 Thread 的 sleep 來獲得更好的可讀性

  yield

    1. 呼叫 yield 會讓當前執行緒從 Running 進入 Runnable 就緒狀態,然後排程執行其它執行緒

    2. 具體的實現依賴於作業系統的任務排程器

五。interrupt 方法

  打斷 sleep,wait,join 的執行緒 這幾個方法都會讓執行緒進入阻塞狀態。

  打斷 sleep 的執行緒, 會清空打斷狀態

  打斷正常執行的執行緒, 不會清空打斷狀態

  打斷 park 執行緒, 不會清空打斷狀態

六。執行緒的5種狀態

  作業系統層面:

   【初始狀態】僅是在語言層面建立了執行緒物件,還未與作業系統執行緒關聯

  【可執行狀態】(就緒狀態)指該執行緒已經被建立(與作業系統執行緒關聯),可以由 CPU 排程執行

  【執行狀態】指獲取了 CPU 時間片執行中的狀態

    當 CPU 時間片用完,會從【執行狀態】轉換至【可執行狀態】,會導致執行緒的上下文切換

  【阻塞狀態】

    如果呼叫了阻塞 API,如 BIO 讀寫檔案,這時該執行緒實際不會用到 CPU,會導致執行緒上下文切換,進入 【阻塞狀態】

    等 BIO 操作完畢,會由作業系統喚醒阻塞的執行緒,轉換至【可執行狀態】

    與【可執行狀態】的區別是,對【阻塞狀態】的執行緒來說只要它們一直不喚醒,排程器就一直不會考慮 排程它們

  【終止狀態】表示執行緒已經執行完畢,生命週期已經結束,不會再轉換為其它狀態

   java層面:

  NEW 執行緒剛被建立,但是還沒有呼叫 start() 方法

  RUNNABLE 當呼叫了 start() 方法之後,注意,Java API 層面的 RUNNABLE 狀態涵蓋了 作業系統 層面的 【可執行狀態】、【執行狀態】和【阻塞狀態】(由於 BIO 導致的執行緒阻塞,在 Java 裡無法區分,仍然認為 是可執行)

  BLOCKED , WAITING , TIMED_WAITING 都是 Java API 層面對【阻塞狀態】的細分。

  TERMINATED 當執行緒程式碼執行結束。