總所周(java程序員)知,Runnable接口是沒有返回值的,但是他的兄弟Callable有返回值。
貼代碼吧。
/**
* 模擬Callable接口的future模式
*/
public class FutureModel {
public static void main(String[] args) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + ":start...");// 主線程開始
// 創建工作對象,相當於Callable變量
Task<String> task = new Task<String>() {
@Override
public String run() {
// 這裏可以放置任何代碼,比如網絡請求,返回響應結果
System.out.println(Thread.currentThread().getName() + ":start...");// 子線程開始
try {
System.out.println(Thread.currentThread().getName() + ":work...");// 子線程工作
Thread.sleep(2000);// 模擬阻塞
int a = 1 / 0;
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":done...");// 子線程結束
return "張5G";
}
};
// FuturePool相當於線程池,這裏是提交任務返回Future對象
FutureData<String> futureData = FuturePool.submit(task);// 這裏不會形成阻塞,主線程繼續運行
System.out.println(Thread.currentThread().getName() + ":work...");// 主線程工作
String result = futureData.get();// 這裏會阻塞調用線程,如主線程阻塞
System.out.println(Thread.currentThread().getName() + ":result:" + result);// 主線程獲取到結果
System.out.println(Thread.currentThread().getName() + ":done...");// 主線程結束
}
}
/**
* 相當於Callable接口
*/
interface Task<T> {
T run();
}
/**
* 真正執行Task中的run方法
*/
class TaskData<T> {
Task<T> task;
T data;
volatile boolean isDone = false;
public TaskData(Task<T> task) {
this.task = task;
}
protected synchronized void doWork() {
try {
data = task.run();
} finally {
isDone = true;
notify();// 喚醒等待的線程
}
}
public synchronized T getFuture() throws InterruptedException {
while (!isDone) {
wait();// 如果沒有執行完一直等待
}
return data;
}
}
/**
* 模擬線程池接收任務,委派線程去執行,所以不會阻塞調用線程
*/
class FuturePool {
public static <T> FutureData<T> submit(Task<T> task) {
FutureData<T> futureData = new FutureData<T>(task);
new Thread(new Runnable() {
@Override
public void run() {
futureData.taskData.doWork();
}
}).start();
return futureData;
}
}
class FutureData<T> {
TaskData<T> taskData;
public FutureData(Task<T> task) {
taskData = new TaskData<T>(task);
}
public T get() throws InterruptedException {
return taskData.getFuture();
}
}