Java concurrency線程池之Callable和Future_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Callable 和 Future 簡介
Callable 和 Future 是比較有趣的一對組合。當(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;
}
說明:從中我們可以看出Callable支持泛型。
2. Future
Future 是一個(gè)接口。它用于表示異步計(jì)算的結(jié)果。提供了檢查計(jì)算是否完成的方法,以等待計(jì)算的完成,并獲取計(jì)算的結(jié)果。
Future的源碼如下:
public interface Future<V> {
// 試圖取消對此任務(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;
}
說明: Future用于表示異步計(jì)算的結(jié)果。它的實(shí)現(xiàn)類是FutureTask,在講解FutureTask之前,我們先看看Callable, Future, FutureTask它們之間的關(guān)系圖,如下:

說明:
(01) RunnableFuture是一個(gè)接口,它繼承了Runnable和Future這兩個(gè)接口。RunnableFuture的源碼如下:
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
(02) FutureTask實(shí)現(xiàn)了RunnableFuture接口。所以,我們也說它實(shí)現(xiàn)了Future接口。
示例和源碼分析(基于JDK1.7.0_40)
我們先通過一個(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對象
Future f1 = pool.submit(c1);
// 輸出結(jié)果
System.out.println(f1.get());
//關(guān)閉線程池
pool.shutdown();
}
}
運(yùn)行結(jié)果:
4950
結(jié)果說明:
在主線程main中,通過newSingleThreadExecutor()新建一個(gè)線程池。接著創(chuàng)建Callable對象c1,然后再通過pool.submit(c1)將c1提交到線程池中進(jìn)行處理,并且將返回的結(jié)果保存到Future對象f1中。然后,我們通過f1.get()獲取Callable中保存的結(jié)果;最后通過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對象
RunnableFuture<T> ftask = newTaskFor(task);
// 執(zhí)行“任務(wù)ftask”
execute(ftask);
// 返回“ftask”
return ftask;
}
說明:submit()通過newTaskFor(task)創(chuàng)建了RunnableFuture對象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對象
this.callable = callable;
// state記錄FutureTask的狀態(tài)
this.state = NEW; // ensure visibility of callable
}
3. FutureTask的run()方法
我們繼續(xù)回到submit()的源碼中。
在newTaskFor()新建一個(gè)ftask對象之后,會通過execute(ftask)執(zhí)行該任務(wù)。此時(shí)ftask被當(dāng)作一個(gè)Runnable對象進(jìn)行執(zhí)行,最終會調(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對象賦值給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);
}
}
說明:run()中會執(zhí)行Callable對象的call()方法,并且最終將結(jié)果保存到result中,并通過set(result)將result保存。
之后調(diào)用FutureTask的get()方法,返回的就是通過set(result)保存的值。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
通過Java實(shí)現(xiàn)在Word中創(chuàng)建可填充表單
這篇文章主要為大家詳細(xì)介紹了如何通過Java代碼,以編程方式在Word中創(chuàng)建可填充表單,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-03-03
Java?-jar參數(shù)設(shè)置小結(jié)
本文主要介紹了Java?-jar參數(shù)設(shè)置小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
SpringBoot項(xiàng)目導(dǎo)出jar包及瘦身部署方式
今天項(xiàng)目要求Nginx+jar包運(yùn)行多個(gè)項(xiàng)目,在此記錄一下部署的過程,其中借鑒了好多網(wǎng)上前輩的經(jīng)驗(yàn),感謝各位的無私分享2024-07-07
java監(jiān)聽器實(shí)現(xiàn)在線人數(shù)統(tǒng)計(jì)
這篇文章主要為大家詳細(xì)介紹了java監(jiān)聽器實(shí)現(xiàn)在線人數(shù)統(tǒng)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11
Java容器ArrayList知識點(diǎn)總結(jié)
本篇文章給大家分享了Java容器ArrayList的相關(guān)知識點(diǎn),對此有需要的朋友可以跟著學(xué)習(xí)參考下。2018-05-05
SpringBoot使用MyBatis-Flex實(shí)現(xiàn)靈活的數(shù)據(jù)庫訪問
MyBatisFlex是一款優(yōu)秀的持久層框架,本文主要介紹了SpringBoot使用MyBatis-Flex實(shí)現(xiàn)靈活的數(shù)據(jù)庫訪問,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06

