在講解 Concurrency 時,我們有必要去理解 Thread 相關知識,因此在此篇文章中,我們講快速理解一遍關於 Thread 的那些事。
什麼是 Thread
要講 Thread 我們就得先談到 Process,我們每一個運行的程序就可稱為為 Process,而 Thread 是 Process 中的執行單位。不過這樣還是有點模糊,我們直接清楚的條列出來以下重點
- 一個 Process 中可以包含一個或多個 Thread。
- 不同的 Process 中是獨立的,且不可共享資源。
- 同一 Process 中的不同 Thread 可以共享 Process 的資源。
除了上述 Process 與 Thread 的說明,接下來我們也需要知道,JVM 與 Process 的關係,重點如下
- Process 其實就是一個運行的程序,當我們 JVM 啟動時,系統就會幫我們分配一個 Process,這個 Process 包含了 JVM 所需的資源,而我們也可以用 JVM 參數來限制 Process 記憶體的劃分。
- 在 JVM 啟動時,我們會啟動一個 Main Thread 來進行應用程序的操作。
在 Java 中應用 Thread
若我們在 Java 裡面要應用 Thread 的話,大概可以包刮以下幾中方式
- 繼承 Thread 類別
- 實現 Runnable 介面
- 使用 Callable 與 Future
- 使用 CompletableFuture
接下來我們就一一實現他。
1. 繼承 Thread 類別
public class Example01 extends Thread {
public void run() {
System.out.println("MyThread running");
}
public static void main(String[] args) {
Example01 thread = new Example01();
thread.start();
}
}
直接繼承 Thread 的方式最為簡單,但我們並不建議使用 Thread 進行設計,原因有以下
- Java 不支持多重繼承,當我們設計好一個 Thread 時,也就代表我們無法繼續的擴展或者繼承其他類。
- Runnable 介面僅表示一個任務,我們很好的將邏輯分離於此處,這也意味著我們可以很好的重用任務。
- 在 Java 中,當我們繼承了,也就代表我們要修改與改進行為,但往往我們繼承 Thread 僅進行 Runnable 的實現。
除了上述三點,我相信還有一些大神可以找出更多點,但目前個人心得如上。
2. 實現 Runnable 介面
public class Example02 implements Runnable {
public void run() {
System.out.println("MyRunnable running");
}
public static void main(String[] args) {
Example02 runnable = new Example02();
Thread thread = new Thread(runnable);
thread.start();
}
}
可以看到我們在 runnable 僅需實現 run 方法,並且邏輯更好的與 Thread 拆分,我今天甚至可以直接使用多個 Thread 來一起執行任務,又或者可以自己進行呼叫來重用任務。
使用 Callable 與 Future
public class Example03 implements Callable<String> {
public String call() throws Exception {
Thread.sleep(5000);
return "Hello, world!";
}
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Example03());
System.out.println("Waiting for result...");
String result = future.get();
System.out.println("Result: " + result);
executor.shutdown();
}
}
在這邊我們可以看到我們大名鼎鼎的 Future 了,在 Java 5 開始提供的 Future 可以讓我們進行任務等待,其實也就是阻塞式獲取執行結果。
使用 CompletableFuture
public class Example04 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
return 1 + 2;
});
future.thenAcceptAsync(result -> {
System.out.println("計算結果為:" + result);
});
System.out.println("請稍等,計算結果正在計算中...");
}
}
在這個例子中我們建立一個 CompletableFuture,並且其計算 1 + 2 結束後,會調用 thenAcceptAsync 來讓我們達成非阻塞式的計算,其運作結果如下
請稍等,計算結果正在計算中...
計算結果為:3
可以看到我們第一行打印的字樣為"請稍等,計算結果正在計算中...",也就代表我們並沒有等待 future 結束,並且我們在另外一個 Thread 執行 thenAcceptAsync 內容。
結論
本篇文章簡單的介紹 Process、Thread、JVM 三者的關係,並且我們實作四種在 Java 中使用 Thread 的方法。在後續我們將進行對 Java Concurrency 更深入的研究與學習。
參考
https://datacadamia.com/os/process/process
https://medium.com/bucketing/java-concurrency-0-%E9%A0%90%E5%85%88%E7%9F%A5%E8%AD%98-338cd98604c2
https://www.geeksforgeeks.org/main-thread-java/