Java並行(三)----建立執行緒的三種方式及檢視程序執行緒

2023-04-25 06:01:37

一、直接使用 Thread

// 建立執行緒物件
Thread t = new Thread() {
    public void run() {
        // 要執行的任務
    }
};
// 啟動執行緒
t.start();

例如:

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

輸出

19:19:00 [t1] c.ThreadStarter - hello

注意:這裡通過@Slf4j註解列印的紀錄檔

二、使用 Runnable

把【執行緒】和【任務】(要執行的程式碼)分開

  • Thread 代表執行緒

  • Runnable 可執行的任務(執行緒要執行的程式碼)

Runnable runnable = new Runnable() {
    public void run(){
        // 要執行的任務
    }
};
// 建立執行緒物件
Thread t = new Thread( runnable );
// 啟動執行緒
t.start(); 

例如:

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

輸出

19:19:00 [t2] c.ThreadStarter - hello

Java 8 以後可以使用 lambda 精簡程式碼

// 建立任務物件
Runnable task2 = () -> log.debug("hello");
​
// 引數1 是任務物件; 引數2 是執行緒名字,推薦
Thread t2 = new Thread(task2, "t2");
t2.start();

小結

  • 方法1 是把執行緒和任務合併在了一起,方法2 是把執行緒和任務分開了

  • 推薦使用用 Runnable,因為 更容易與執行緒池等高階 API 配合

  • 用 Runnable 讓任務類脫離了 Thread 繼承體系,更靈活

三、FutureTask

FutureTask (未來任務)能夠接收 Callable 型別的引數,用來處理有返回結果的情況

// 建立任務物件
FutureTask<Integer> task3 = new FutureTask<>(() -> {
    log.debug("hello");
    Thread.sleep(2000);
    return 100;
});
​
// 引數1 是任務物件; 引數2 是執行緒名字,推薦
new Thread(task3, "t3").start();
​
// 執行到這裡主執行緒阻塞,會同步等待 task 執行完畢的結果
Integer result = task3.get();
log.debug("結果是:{}", result);

輸出

19:22:27 [t3] c.ThreadStarter - hello
19:22:29 [main] c.ThreadStarter - 結果是:100

可以看到兩秒後主執行緒返回結果

四、觀察多個執行緒同時執行

主要是理解

  • 交替執行

  • 誰先誰後,執行緒的執行不由我們控制

程式碼

    public static void main(String[] args) {
        new Thread(() -> {
            while(true) {
                log.debug("running");
            }
        },"t1").start();
        new Thread(() -> {
            while(true) {
                log.debug("running");
            }
        },"t2").start();
    }

結果

可以看到,執行緒是交替執行的。但是誰先誰後不是我們控制的。但是如果是單核CPU的話執行這段程式的話,只會有一個執行緒開始執行。

五、檢視程序執行緒

5.1 windows

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

  • 控制檯tasklist 檢視程序

  • 控制檯taskkill /F /PID pid編號 殺死程序

5.2 linux

  • ps -fe 檢視所有程序

  • ps -fe | grep 關鍵詞 檢視所有程序

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

  • kill 殺死程序

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

  • top -H -p <PID> 檢視某個程序(PID)的所有執行緒,可持續檢視執行緒的狀態

5.3 Java

  • jps 命令檢視所有 Java 程序

  • jstack <PID> 檢視某個 Java 程序(PID)的所有執行緒狀態 ,只能檢視某一刻某個程序所有執行緒較詳細的狀態

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

  • 如果是從命令列啟動,使 JDK 在 PATH 上,執行 jconsole 即可;如果從 GUI shell 啟動,找到 JDK 安裝路徑,開啟 bin 資料夾,雙擊 jconsole

  jconsole 遠端監控設定

  • 需要以如下方式執行你的 java 類

java -Djava.rmi.server.hostname=`ip地址` -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=`連線埠` -Dcom.sun.management.jmxremote.ssl=是否安全連線 -Dcom.sun.management.jmxremote.authenticate=是否認證 java類
  • 修改 /etc/hosts 檔案將 127.0.0.1 對映至主機名

如果要認證存取,還需要做如下步驟

  • 複製 jmxremote.password 檔案

  • 修改 jmxremote.password 和 jmxremote.access 檔案的許可權為 600 即檔案所有者可讀寫

  • 連線時填入 controlRole(使用者名稱),R&D(密碼)

這種方式瞭解一下即可。對於生產環境一般沒有許可權存取的。