Table of Contents
ToggleCallable in Java with Examples
定義了一個 泛型 V 傳回值的 call 方法,會拋出檢查例外,因此可輕易地將例外往外傳遞,當任務完成時使用 Future 儲存不同執行緒的結果, Callable Java 基本上是主執行緒可以追踪其他執行緒的進度結果的一種方式,FutureTask 實作了 Runnable 和 Future 介面,方便地結合了這兩種功能, Callable in Java 本篇增加了範例,並透過單元測試來驗證產出結果。
檔案目錄
./
+- src
+- test
| +- org
| +- ruoxue
| +- java_147
| +- multithreading
| +- callable
| +- CallableWithExamplesTest.java
單元測試
Callable Java 提供執行任務、拋出例外、傳回值等操作。
worker
Callable Java 建立 3 條執行緒,執行 3 個任務,每個任務耗時 3 秒完成,主執行緒會無限等待取得每個任務結束後的傳回值。
protected class Worker implements Callable<Object> {
private int id;
private Object result;
public Worker(int id) {
this.id = id;
}
public int getId() {
return id;
}
@Override
public Object call() throws 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(3);
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
result = "OK";
return result;
}
}
@Test
public void worker() {
try {
int taskSize = 3;
List<FutureTask<Object>> futureTasks = new ArrayList<FutureTask<Object>>();
for (int i = 0; i < taskSize; i++) {
FutureTask<Object> futureTask = new FutureTask<Object>(new Worker(i));
futureTasks.add(futureTask);
Thread thread = new Thread(futureTask);
thread.start();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
futureTasks.forEach(e -> {
try {
Object result = e.get();
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
}
2023/02/07 08:20:39 T[12] worker: 1 ready
2023/02/07 08:20:39 T[11] worker: 0 ready
2023/02/07 08:20:39 T[13] worker: 2 ready
2023/02/07 08:20:42 T[13] worker: 2 finished
2023/02/07 08:20:42 T[12] worker: 1 finished
2023/02/07 08:20:42 T[11] worker: 0 finished
2023/02/07 08:20:42 T[1] worker: OK
2023/02/07 08:20:42 T[1] worker: OK
2023/02/07 08:20:42 T[1] worker: OK
brokenWorker
Callable Java 建立 3 條執行緒,執行 3 個任務,每個任務耗時 1 秒完成,其中 1 條執行緒拋出例外,主執行緒會無限等待取得每個任務結束後的傳回值。
protected class BrokenWorker implements Callable<Object> {
private int id;
private Object result;
public BrokenWorker(int id) {
this.id = id;
}
public int getId() {
return id;
}
@Override
public Object call() throws Exception {
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(3);
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
result = "OK";
return result;
}
}
@Test
public void brokenWorker() {
try {
int taskSize = 3;
List<FutureTask<Object>> futureTasks = new ArrayList<FutureTask<Object>>();
for (int i = 0; i < taskSize; i++) {
FutureTask<Object> futureTask = new FutureTask<Object>(new BrokenWorker(i));
futureTasks.add(futureTask);
Thread thread = new Thread(futureTask);
thread.start();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
futureTasks.forEach(e -> {
try {
Object result = e.get();
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
}
2023/02/07 08:22:17 T[16] worker: 2 ready
2023/02/07 08:22:17 T[14] worker: 0 ready
2023/02/07 08:22:20 T[14] worker: 0 finished
2023/02/07 08:22:20 T[16] worker: 2 finished
2023/02/07 08:22:20 T[1] worker: OK
java.util.concurrent.ExecutionException: java.lang.RuntimeException: BrokenWorker 1 throw exception
2023/02/07 08:22:20 T[1] worker: OK
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at org.ruoxue.java_147.multithreading.CallableWithExamplesTest.lambda$1(CallableWithExamplesTest.java:114)
at java.util.ArrayList.forEach(ArrayList.java:1257)
CallableWithExamplesTest.java
Java Runnable 新增單元測試,驗證是否符合預期。
package org.ruoxue.java_147.multithreading.callable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
public class CallableWithExamplesTest {
protected class Worker implements Callable<Object> {
private int id;
private Object result;
public Worker(int id) {
this.id = id;
}
public int getId() {
return id;
}
@Override
public Object call() throws 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(3);
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
result = "OK";
return result;
}
}
@Test
public void worker() {
try {
int taskSize = 3;
List<FutureTask<Object>> futureTasks = new ArrayList<FutureTask<Object>>();
for (int i = 0; i < taskSize; i++) {
FutureTask<Object> futureTask = new FutureTask<Object>(new Worker(i));
futureTasks.add(futureTask);
Thread thread = new Thread(futureTask);
thread.start();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
futureTasks.forEach(e -> {
try {
Object result = e.get();
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
}
protected class BrokenWorker implements Callable<Object> {
private int id;
private Object result;
public BrokenWorker(int id) {
this.id = id;
}
public int getId() {
return id;
}
@Override
public Object call() throws Exception {
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(3);
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
result = "OK";
return result;
}
}
@Test
public void brokenWorker() {
try {
int taskSize = 3;
List<FutureTask<Object>> futureTasks = new ArrayList<FutureTask<Object>>();
for (int i = 0; i < taskSize; i++) {
FutureTask<Object> futureTask = new FutureTask<Object>(new BrokenWorker(i));
futureTasks.add(futureTask);
Thread thread = new Thread(futureTask);
thread.start();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
futureTasks.forEach(e -> {
try {
Object result = e.get();
System.out.println(
sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
心得分享
Callable in Java Multithreading 提供建立新執行緒,執行指定任務,使用 Java Callable 可以拋出設計階段的檢查例外,像是: IOException ,及取得不同執行緒的結果,多執行緒一直以來,都是 Java 的主要方面,使用 Callable Java 進而優化系統資源,提升執行效率。