Java concurrency線程池之Callable和Future_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Callable 和 Future 簡(jiǎn)介
Callable 和 Future 是比較有趣的一對(duì)組合。當(dāng)我們需要獲取線程的執(zhí)行結(jié)果時(shí),就需要用到它們。Callable用于產(chǎn)生結(jié)果,F(xiàn)uture用于獲取結(jié)果。
1. Callable
Callable 是一個(gè)接口,它只包含一個(gè)call()方法。Callable是一個(gè)返回結(jié)果并且可能拋出異常的任務(wù)。
為了便于理解,我們可以將Callable比作一個(gè)Runnable接口,而Callable的call()方法則類似于Runnable的run()方法。
Callable的源碼如下:
public interface Callable<V> {
V call() throws Exception;
}
說(shuō)明:從中我們可以看出Callable支持泛型。
2. Future
Future 是一個(gè)接口。它用于表示異步計(jì)算的結(jié)果。提供了檢查計(jì)算是否完成的方法,以等待計(jì)算的完成,并獲取計(jì)算的結(jié)果。
Future的源碼如下:
public interface Future<V> {
// 試圖取消對(duì)此任務(wù)的執(zhí)行。
boolean cancel(boolean mayInterruptIfRunning)
// 如果在任務(wù)正常完成前將其取消,則返回 true。
boolean isCancelled()
// 如果任務(wù)已完成,則返回 true。
boolean isDone()
// 如有必要,等待計(jì)算完成,然后獲取其結(jié)果。
V get() throws InterruptedException, ExecutionException;
// 如有必要,最多等待為使計(jì)算完成所給定的時(shí)間之后,獲取其結(jié)果(如果結(jié)果可用)。
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
說(shuō)明: Future用于表示異步計(jì)算的結(jié)果。它的實(shí)現(xiàn)類是FutureTask,在講解FutureTask之前,我們先看看Callable, Future, FutureTask它們之間的關(guān)系圖,如下:

說(shuō)明:
(01) RunnableFuture是一個(gè)接口,它繼承了Runnable和Future這兩個(gè)接口。RunnableFuture的源碼如下:
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
(02) FutureTask實(shí)現(xiàn)了RunnableFuture接口。所以,我們也說(shuō)它實(shí)現(xiàn)了Future接口。
示例和源碼分析(基于JDK1.7.0_40)
我們先通過(guò)一個(gè)示例看看Callable和Future的基本用法,然后再分析示例的實(shí)現(xiàn)原理。
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ExecutionException;
class MyCallable implements Callable {
@Override
public Integer call() throws Exception {
int sum = 0;
// 執(zhí)行任務(wù)
for (int i=0; i<100; i++)
sum += i;
//return sum;
return Integer.valueOf(sum);
}
}
public class CallableTest1 {
public static void main(String[] args)
throws ExecutionException, InterruptedException{
//創(chuàng)建一個(gè)線程池
ExecutorService pool = Executors.newSingleThreadExecutor();
//創(chuàng)建有返回值的任務(wù)
Callable c1 = new MyCallable();
//執(zhí)行任務(wù)并獲取Future對(duì)象
Future f1 = pool.submit(c1);
// 輸出結(jié)果
System.out.println(f1.get());
//關(guān)閉線程池
pool.shutdown();
}
}
運(yùn)行結(jié)果:
4950
結(jié)果說(shuō)明:
在主線程main中,通過(guò)newSingleThreadExecutor()新建一個(gè)線程池。接著創(chuàng)建Callable對(duì)象c1,然后再通過(guò)pool.submit(c1)將c1提交到線程池中進(jìn)行處理,并且將返回的結(jié)果保存到Future對(duì)象f1中。然后,我們通過(guò)f1.get()獲取Callable中保存的結(jié)果;最后通過(guò)pool.shutdown()關(guān)閉線程池。
1. submit()
submit()在java/util/concurrent/AbstractExecutorService.java中實(shí)現(xiàn),它的源碼如下:
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
// 創(chuàng)建一個(gè)RunnableFuture對(duì)象
RunnableFuture<T> ftask = newTaskFor(task);
// 執(zhí)行“任務(wù)ftask”
execute(ftask);
// 返回“ftask”
return ftask;
}
說(shuō)明:submit()通過(guò)newTaskFor(task)創(chuàng)建了RunnableFuture對(duì)象ftask。它的源碼如下:
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
2. FutureTask的構(gòu)造函數(shù)
FutureTask的構(gòu)造函數(shù)如下:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
// callable是一個(gè)Callable對(duì)象
this.callable = callable;
// state記錄FutureTask的狀態(tài)
this.state = NEW; // ensure visibility of callable
}
3. FutureTask的run()方法
我們繼續(xù)回到submit()的源碼中。
在newTaskFor()新建一個(gè)ftask對(duì)象之后,會(huì)通過(guò)execute(ftask)執(zhí)行該任務(wù)。此時(shí)ftask被當(dāng)作一個(gè)Runnable對(duì)象進(jìn)行執(zhí)行,最終會(huì)調(diào)用到它的run()方法;ftask的run()方法在java/util/concurrent/FutureTask.java中實(shí)現(xiàn),源碼如下:
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
// 將callable對(duì)象賦值給c。
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// 執(zhí)行Callable的call()方法,并保存結(jié)果到result中。
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
// 如果運(yùn)行成功,則將result保存
if (ran)
set(result);
}
} finally {
runner = null;
// 設(shè)置“state狀態(tài)標(biāo)記”
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
說(shuō)明:run()中會(huì)執(zhí)行Callable對(duì)象的call()方法,并且最終將結(jié)果保存到result中,并通過(guò)set(result)將result保存。
之后調(diào)用FutureTask的get()方法,返回的就是通過(guò)set(result)保存的值。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JUnit測(cè)試控制@Test執(zhí)行順序的三種方式小結(jié)
這篇文章主要介紹了JUnit測(cè)試控制@Test執(zhí)行順序的三種方式小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
springboot無(wú)法跳轉(zhuǎn)頁(yè)面的問(wèn)題解決方案
這篇文章主要介紹了springboot無(wú)法跳轉(zhuǎn)頁(yè)面的問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09
SpringBoot?AOP?@Pointcut切入點(diǎn)表達(dá)式排除某些類方式
這篇文章主要介紹了SpringBoot?AOP?@Pointcut切入點(diǎn)表達(dá)式排除某些類方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Java Swing JToggleButton開(kāi)關(guān)按鈕的實(shí)現(xiàn)
這篇文章主要介紹了Java Swing JToggleButton開(kāi)關(guān)按鈕的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
java開(kāi)發(fā)工作中對(duì)InheritableThreadLocal使用思考
這篇文章主要為大家介紹了java開(kāi)發(fā)工作中對(duì)InheritableThreadLocal使用思考詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
面試官:Java中new Object()到底占用幾個(gè)字節(jié)
這篇文章主要介紹了面試官:Java中new Object()到底占用幾個(gè)字節(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02

