Table of Contents
ToggleRunnable in Java with Examples
有兩種方法可以啟動一個新執行緒,實作 Runnable Interface 或繼承 Thread ,覆寫 run 方法, Thread 有一個接受 Runnable 的建構子,將實現者傳給 Thread ,然後調用 start 建立一個新執行緒,此緒會執行 run 中的程式碼, Runnable in Java 本篇增加了範例,並透過單元測試來驗證產出結果。
檔案目錄
./
+- src
+- test
| +- org
| +- ruoxue
| +- java_147
| +- multithreading
| +- runnable
| +- RunnableWithExamplesTest.java
單元測試
Runnable Java 提供執行、拋出例外等操作。
task
Java Runnable 可使用繼承 Thread 覆寫 run 方法,建立 3 條執行緒,執行 3 個任務,每個任務耗時 1 秒完成,主執行緒等待 3 秒才結束任務。
protected class Task extends Thread {
private int id;
public Task(int id) {
this.id = id;
}
@Override
public void run() {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
TimeUnit.SECONDS.sleep(1);
System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id
+ " finished");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
@Test
public void task() {
try {
int taskSize = 3;
for (int i = 0; i < taskSize; i++) {
Thread thread = new Thread(new Task(i));
thread.start();
}
TimeUnit.SECONDS.sleep(3);
} catch (Exception ex) {
ex.printStackTrace();
}
}
2023/02/06 03:18:44 T[12] worker: 0 ready
2023/02/06 03:18:44 T[16] worker: 2 ready
2023/02/06 03:18:44 T[14] worker: 1 ready
2023/02/06 03:18:45 T[12] worker: 0 finished
2023/02/06 03:18:45 T[16] worker: 2 finished
2023/02/06 03:18:45 T[14] worker: 1 finished
worker
Java Runnable 也可使用實作 Runnable Interface 的 run 方法,建立 3 條執行緒,執行 3 個任務,每個任務耗時 1 秒完成,調用 join 讓主執行緒等待 3 條執行緒全部完成才結束任務。
protected class Worker implements Runnable {
private int id;
public Worker(int id) {
this.id = id;
}
@Override
public void run() {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
TimeUnit.SECONDS.sleep(1);
System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id
+ " finished");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
@Test
public void worker() {
int taskSize = 3;
List<Thread> threads = new ArrayList<Thread>();
IntStream.range(0, taskSize).forEach(e -> {
Thread thread = new Thread(new Worker(e));
thread.start();
threads.add(thread);
});
threads.forEach(e -> {
try {
e.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
}
2023/02/06 03:19:33 T[12] worker: 1 ready
2023/02/06 03:19:33 T[11] worker: 0 ready
2023/02/06 03:19:33 T[13] worker: 2 ready
2023/02/06 03:19:34 T[13] worker: 2 finished
2023/02/06 03:19:34 T[12] worker: 1 finished
2023/02/06 03:19:34 T[11] worker: 0 finished
brokenWorker
Runnable Java 建立 3 條執行緒,執行 3 個任務,每個任務耗時 1 秒完成,其中 1 條執行緒拋出例外,調用 join 讓主執行緒等待 3 條執行緒全部完成才結束任務。
protected class BrokenWorker implements Runnable {
private int id;
public BrokenWorker(int id) {
this.id = id;
}
@Override
public void run() {
try {
if (id == 1) {
throw new RuntimeException("BrokenWorker " + id + " throw exception");
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
TimeUnit.SECONDS.sleep(1);
System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id
+ " finished");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
@Test
public void brokenWorker() {
int taskSize = 3;
AtomicInteger ids = new AtomicInteger();
List<Thread> threads = Stream.generate(() -> new Thread(new BrokenWorker(ids.getAndIncrement())))
.limit(taskSize).collect(Collectors.toList());
threads.forEach(e -> e.start());
threads.forEach(e -> {
try {
e.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
}
java.io.IOException: BrokenWorker 1 throw exception
at org.ruoxue.java_147.multithreading.RunnableWithExamplesTest$BrokenWorker.run(RunnableWithExamplesTest.java:110)
at java.lang.Thread.run(Thread.java:750)
2023/02/06 03:23:24 T[11] worker: 0 ready
2023/02/06 03:23:24 T[13] worker: 2 ready
2023/02/06 03:23:25 T[11] worker: 0 finished
2023/02/06 03:23:25 T[13] worker: 2 finished
RunnableWithExamplesTest.java
Java Runnable 新增單元測試,驗證是否符合預期。
package org.ruoxue.java_147.multithreading.runnable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.Test;
public class RunnableWithExamplesTest {
protected class Task extends Thread {
private int id;
public Task(int id) {
this.id = id;
}
@Override
public void run() {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
TimeUnit.SECONDS.sleep(1);
System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id
+ " finished");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
@Test
public void task() {
try {
int taskSize = 3;
for (int i = 0; i < taskSize; i++) {
Thread thread = new Thread(new Task(i));
thread.start();
}
TimeUnit.SECONDS.sleep(3);
} catch (Exception ex) {
ex.printStackTrace();
}
}
protected class Worker implements Runnable {
private int id;
public Worker(int id) {
this.id = id;
}
@Override
public void run() {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
TimeUnit.SECONDS.sleep(1);
System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id
+ " finished");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
@Test
public void worker() {
int taskSize = 3;
List<Thread> threads = new ArrayList<Thread>();
IntStream.range(0, taskSize).forEach(e -> {
Thread thread = new Thread(new Worker(e));
thread.start();
threads.add(thread);
});
threads.forEach(e -> {
try {
e.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
}
protected class BrokenWorker implements Runnable {
private int id;
public BrokenWorker(int id) {
this.id = id;
}
@Override
public void run() {
try {
if (id == 1) {
throw new RuntimeException("BrokenWorker " + id + " throw exception");
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
TimeUnit.SECONDS.sleep(1);
System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id
+ " finished");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
@Test
public void brokenWorker() {
int taskSize = 3;
AtomicInteger ids = new AtomicInteger();
List<Thread> threads = Stream.generate(() -> new Thread(new BrokenWorker(ids.getAndIncrement())))
.limit(taskSize).collect(Collectors.toList());
threads.forEach(e -> e.start());
threads.forEach(e -> {
try {
e.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
}
}
心得分享
Runnable in Java Multithreading 多執行緒一直以來,都是 Java 的主要方面,提供建立新執行緒,執行指定任務,使用 Java Runnable 不能拋出設計階段的檢查例外,像是: FileNotFoundException ,但是可以拋出執行階段的執行例外,如: RuntimeException ,多執行緒程式包含兩個或多個可以並發執行的部分,每個部分可以同時處理不同的任務,Runnable Java 進而優化利用可用資源。