Futrue Task 是 J.U.C 的組件 , 但不是 AQS 的子類
Futrue Task
我們知道在 Java
中 , 創(chuàng)建一個(gè)線程有兩種方法 , 一種是直接繼承Thread
, 另外一種是實(shí)現(xiàn) Runable
接口 , 但是這兩種方式都有一個(gè)共同的缺陷是 , 它們?cè)趫?zhí)行為任務(wù)時(shí), 都無(wú)法獲取到任務(wù)的結(jié)果 . 在 jdk 1.5
之后 , 提供了Callable
和 Future
, 通過它倆可以在任務(wù)執(zhí)行修改完畢之后得到任務(wù)的執(zhí)行結(jié)果 .
Callable 和 Runable 接口對(duì)比
Runable
比較簡(jiǎn)單, 它是一個(gè)接口, 而且只有一個(gè)方法 run()
, Callable
也較為簡(jiǎn)單, 不同的是 它是一個(gè)泛型的接口 , 它有一個(gè) call()
函數(shù) , 這個(gè)函數(shù)的返回類型就是我們創(chuàng)建 Callable
傳進(jìn)去的類型, 兩者比較相比, Callable
功能較強(qiáng)大一些, 主要是其被線程執(zhí)行后有返回值, 并且能拋出異常 .
Future接口
對(duì)于 Callable
或者 Future
的任務(wù) , Futrue
可以對(duì)其取消 , 查詢其任務(wù)是否被取消, 查詢?nèi)蝿?wù)是否完成, 已經(jīng)獲取結(jié)果等 . 通常線程都是屬于異步計(jì)算模型的, 你不可嫩從別的線程得到方法的返回值 , 這個(gè)時(shí)候 Futrue
就派上用場(chǎng)了 , Futrue
可以監(jiān)視目標(biāo)線程調(diào)用 call()
的情況, 當(dāng)你調(diào)用 Futrue
get()
方法的時(shí)候 , 就可以獲得它的結(jié)果 , 這個(gè)時(shí)候通常線程不會(huì)直接完成, 當(dāng)前線程就開始阻塞 , 直到 call()
方法返回結(jié)果, 線程才繼續(xù)執(zhí)行 . 總之就是, Futrue
可以得到別的線程任務(wù)方法的返回值 .
Futrue Task 類
其父類是 RunableFutrue
, 而 Runable Futrue
繼承了 Runable 和 Futrue
這兩個(gè)接口 . 所以 Futrue Task
最后執(zhí)行的也是 Callable
類型的任務(wù) .
/**
* A {@link Future} that is {@link Runnable}. Successful execution of
* the {@code run} method causes completion of the {@code Future}
* and allows access to its results.
* @see FutureTask
* @see Executor
* @since 1.6
* @author Doug Lea
* @param <V> The result type returned by this Future's {@code get} method
*/
public interface RunnableFuture<V> extends Runnable, Future<V> {
// 繼承了 Runnable 和 Future
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
如果構(gòu)造函數(shù)數(shù) Runable
的話 ,它或轉(zhuǎn)換成 Callable
類型. Futrue Task
實(shí)現(xiàn)了 兩個(gè)接口 Runable
和 Futrue
, 所以它既可以作為Runable
被線程執(zhí)行 , 又可以作為 Futrue
得到 Callable
的返回值 . 這兩個(gè)接口的組合有什么優(yōu)點(diǎn)呢 , 比如說(shuō) , 有一個(gè)很費(fèi)時(shí)邏輯需要計(jì)算, 并返回結(jié)果, 同時(shí)這個(gè)值又不是馬上需要, 就可以使用它, 用另外一個(gè)線程去就按返回值, 而當(dāng)前現(xiàn)在在使用這個(gè)返回值之前可以做其他的操作,等到需要這個(gè)返回值的時(shí)候, 再通過 Future
得到 .
代碼實(shí)例
- Future 代碼示例
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@Slf4j
public class FutureExample {
// 定義一個(gè)Callable的任務(wù) MyCallable , 這里返回一個(gè)String 類型
static class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
// 假如 在這個(gè)callable 做一些事情需要比較長(zhǎng)時(shí)間 , 咱們讓線程 sleep 5s
log.info("do something in callable");
Thread.sleep(5000);
// 任務(wù)完成了 返回 Done
return "Done";
}
}
public static void main(String[] args) throws Exception {
// 使用Future和 Callable 的時(shí)候一般是通過線程池類調(diào)用的 . 在這里 申明一個(gè)線程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 讓線程池直接提交該任務(wù) , 返回任務(wù)結(jié)果
// 這樣就相當(dāng)于用 Future 接收了另外一個(gè)線程任務(wù)計(jì)算的結(jié)果
Future<String> future = executorService.submit(new MyCallable());
log.info("do something in main");
Thread.sleep(1000);
// 獲取之前的任務(wù)返回了什么結(jié)果
String result = future.get();
log.info("result:{}", result);
}
}
- Future Task 示例
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
@Slf4j
public class FutureTaskExample {
public static void main(String[] args) throws Exception {
FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
log.info("do something in callable");
Thread.sleep(5000);
return "Done";
}
});
new Thread(futureTask).start();
log.info("do something in main");
Thread.sleep(1000);
String result = futureTask.get();
log.info("result:{}", result);
}
}
上兩示例代碼結(jié)果輸出 如下圖
總結(jié)
FutureTask
是將 Future
和 Callable
相關(guān)的東西都結(jié)合在一起了, 所以在他們?nèi)齻€(gè)之間 , 使用 FutureTask
就可以解決你想做的事情 . 如果在Java
程序中, 如果你想起一個(gè)線程去做一些事情的時(shí)候, 并且你還希望獲得線程的結(jié)果已經(jīng)它是否正常執(zhí)行, 就可以使用 FutureTask
.