進程與線程是作業系統的調度單位,可視為系統「資源」。Java 作為跨平台語言,透過 Process 與 Thread 類封裝底層功能。本文深入探討 Java 如何建立進程/線程、JVM 如何實現這些封裝、以及 Java 封裝與原生 OS 機制的異同與限制。
java.lang.Process:抽象類ProcessImpl:JDK 內部實現類ProcessBuilder(JDK 1.5+):提供更靈活的進程配置(環境變數、工作目錄、流合併)// Runtime.exec 多重載形式
Process exec(String command)
Process exec(String[] cmdArray, String[] envp, File dir)
// ProcessBuilder 鏈式配置
Process p = new ProcessBuilder("cmd", "arg1").start();
ProcessBuilder pb = new ProcessBuilder("cmd", "arg1");
pb.environment().put("VAR", "value");
pb.directory(new File("/workdir"));
Process p = pb.start();
ProcessBuilder 最大優勢在於可預先配置屬性並複用,修改屬性僅影響後續建立的進程。
ProcessImpl 透過 native 方法呼叫 Windows API:
| JDK Native 方法 | Windows API |
|---|---|
| create | CreateProcess, CreatePipe |
| close | CloseHandle |
| waitFor | WaitForMultipleObjects |
| destroy | TerminateProcess |
| exitValue | GetExitCodeProcess |
以 create 為例,JVM 建立管道、轉換參數格式、呼叫 CreateProcess、取得進程句柄並返回。JVM 盡可能封裝平台細節,體現跨平台特性。
cmd.exe|)與重定向(>)無法直接透過參數傳遞,需在 Java 代碼中處理流// 繼承 Thread
class MyThread extends Thread {
public void run() { System.out.println("Started"); }
}
new MyThread().start();
// 實作 Runnable
class MyRunnable implements Runnable {
public void run() { System.out.println("Running"); }
}
new Thread(new MyRunnable()).start();
本質上皆是實作 run() 方法作為線程入口。
Thread.start() 呼叫 native start0()Thread.registerNatives() 註冊本地方法(靜態區塊自動執行)JVM_StartThread 建立平台原生線程,線程函數為 thread_entrythread_entry 透過 JNI 呼叫 Java 線程的 run() 方法// 關鍵調用鏈 Thread.start() → start0() → JVM_StartThread() → thread_entry() → run()
直接呼叫 run() 不會建立新線程,僅在當前線程執行。
一對一模型:每個 Java 線程對應一個原生線程。但 Java 封裝帶來限制:
join() 僅支援等待單一線程,無法實現「任一線程結束」或「所有線程結束」等複雜同步Thread.getId() 返回內部計數器,與 OS 線程 ID 無關Java 封裝降低了開發複雜度,提升效率,但也屏蔽了 OS 原生特性,導致上述限制。隨著 Java 演進,封裝功能子集將更加完善,開發者需理解底層機制以避免潛在陷阱。