詳解Java中Callable和Future的區(qū)別
Java中為什么需要Callable
在java中有兩種創(chuàng)建線程的方法:
一種是繼承Thread類,重寫run方法:
public class TestMain {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
}
}
class MyThread extends Thread {
public void run() {
System.out.println("MyThread running...");
}
}第二種是使用Runnable創(chuàng)建一個(gè)線程:
public class TestMain {
public static void main(String[] args) {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Thread created with runnable running...");
}
};
Thread t1 = new Thread(r1);
t1.start();
}
}其實(shí)這兩種方式,底層都是執(zhí)行Thread類的run方法:

無(wú)論使用這里的哪種方式創(chuàng)建線程,都無(wú)法在線程結(jié)束時(shí)return一個(gè)返回值。但是在非常多的場(chǎng)景下,我們都需要在線程執(zhí)行結(jié)束時(shí),將執(zhí)行的結(jié)果封裝為一個(gè)返回值返回給主線程(或者調(diào)用者線程)。因此java在1.5版本時(shí),在java.util.concurrent包引入了Callable接口,用于線程執(zhí)行完時(shí)return一個(gè)返回值。
Callable和Runnable的區(qū)別
Runnable和Callable都是接口,分別定義如下:
package java.lang;
?
/**
* The <code>Runnable</code> interface should be implemented by any
* class whose instances are intended to be executed by a thread. The
* class must define a method of no arguments called <code>run</code>.
* <p>
* @since JDK1.0
*/
@FunctionalInterface
public interface Runnable {
public abstract void run();
}package java.util.concurrent;
?
/**
* A task that returns a result and may throw an exception.
* Implementors define a single method with no arguments called
* {@code call}.
*
* <p>The {@code Callable} interface is similar to {@link
* java.lang.Runnable}, in that both are designed for classes whose
* instances are potentially executed by another thread. A
* {@code Runnable}, however, does not return a result and cannot
* throw a checked exception.
*
* <p>The {@link Executors} class contains utility methods to
* convert from other common forms to {@code Callable} classes.
*
* @see Executor
* @since 1.5
* @author Doug Lea
* @param <V> the result type of method {@code call}
*/
@FunctionalInterface
public interface Callable<V> {
/**
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}可以看出,Callable和Runnable主要有兩點(diǎn)區(qū)別:
- 有返回值;
- 可以拋出異常(這里拋出的異常,會(huì)在future.get()時(shí)可以通過(guò)
ExectionException捕獲);
因此可以看出,Callable更加實(shí)用。這里舉個(gè)Callable使用的例子:
Callable callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int i = new Random().nextInt(5);
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return i;
}
};雖然Callable接口的call方法可以返回執(zhí)行結(jié)果,但是有兩個(gè)問(wèn)題需要解決:
- 線程的創(chuàng)建只能通過(guò)
Runnable,通過(guò)Callable又如何創(chuàng)建線程? - 如何獲取執(zhí)行結(jié)果?
答案是Future和RunnableFuture。
Future和RunnableFuture
Future是一個(gè)接口,看下定義:
package java.util.concurrent;
?
/**
* A {@code Future} represents the result of an asynchronous
* computation. Methods are provided to check if the computation is
* complete, to wait for its completion, and to retrieve the result of
* the computation. The result can only be retrieved using method
* {@code get} when the computation has completed, blocking if
* necessary until it is ready. Cancellation is performed by the
* {@code cancel} method. Additional methods are provided to
* determine if the task completed normally or was cancelled. Once a
* computation has completed, the computation cannot be cancelled.
* If you would like to use a {@code Future} for the sake
* of cancellability but not provide a usable result, you can
* declare types of the form {@code Future<?>} and
* return {@code null} as a result of the underlying task.
*
* @see FutureTask
* @see Executor
* @since 1.5
* @author Doug Lea
* @param <V> The result type returned by this Future's {@code get} method
*/
public interface Future<V> {
?
/**
* Attempts to cancel execution of this task. This attempt will
* fail if the task has already completed, has already been cancelled,
* or could not be cancelled for some other reason. If successful,
* and this task has not started when {@code cancel} is called,
* this task should never run. If the task has already started,
* then the {@code mayInterruptIfRunning} parameter determines
* whether the thread executing this task should be interrupted in
* an attempt to stop the task.
*
* <p>After this method returns, subsequent calls to {@link #isDone} will
* always return {@code true}. Subsequent calls to {@link #isCancelled}
* will always return {@code true} if this method returned {@code true}.
*
* @param mayInterruptIfRunning {@code true} if the thread executing this
* task should be interrupted; otherwise, in-progress tasks are allowed
* to complete
* @return {@code false} if the task could not be cancelled,
* typically because it has already completed normally;
* {@code true} otherwise
*/
boolean cancel(boolean mayInterruptIfRunning);
?
/**
* Returns {@code true} if this task was cancelled before it completed
* normally.
*
* @return {@code true} if this task was cancelled before it completed
*/
boolean isCancelled();
?
/**
* Returns {@code true} if this task completed.
*
* Completion may be due to normal termination, an exception, or
* cancellation -- in all of these cases, this method will return
* {@code true}.
*
* @return {@code true} if this task completed
*/
boolean isDone();
?
/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
*/
V get() throws InterruptedException, ExecutionException;
?
/**
* Waits if necessary for at most the given time for the computation
* to complete, and then retrieves its result, if available.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
* @throws TimeoutException if the wait timed out
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}可以看出,Future可以用來(lái)表示線程的未來(lái)執(zhí)行結(jié)果:一個(gè)容器,這個(gè)容器內(nèi)將來(lái)存放的是線程的執(zhí)行結(jié)果,線程執(zhí)行完之前該容器內(nèi)沒(méi)有值,但是線程一旦執(zhí)行成功(Callable的call方法返回之后),就會(huì)將結(jié)果存入該容器。從Future的接口定義可看出,Future不僅支持阻塞獲取執(zhí)行結(jié)果,還支持取消任務(wù)的執(zhí)行,判斷任務(wù)是否執(zhí)行完成等。因此通過(guò)Future,主線程(或者調(diào)用者線程)可以跟進(jìn)子現(xiàn)場(chǎng)的執(zhí)行情況。
Callable其實(shí)和Runnable很像,都會(huì)執(zhí)行一個(gè)任務(wù),只不過(guò)Callable可以返回執(zhí)行的結(jié)果。一般將執(zhí)行結(jié)果封裝到Future,調(diào)用者線程即可以通過(guò)Future獲取Callable的執(zhí)行結(jié)果了。因此,一般Callable會(huì)和Future搭配使用。
但是問(wèn)題來(lái)了:java創(chuàng)建線程,需要Runnable,獲取執(zhí)行結(jié)果又需要Future。因此RunnableFuture來(lái)了:

可以看出,通過(guò)RunnableFuture,既可以創(chuàng)建線程,又可以獲取線程的執(zhí)行結(jié)果,當(dāng)然RunnableFuture也是一個(gè)接口,我們一般情況下會(huì)使用它的具體實(shí)現(xiàn)類FutureTask。
那可能又有人要問(wèn)了,Callable又是如何建立聯(lián)系的呢?看下FutureTask的使用方式就明白了:
public class TestMain {
public static void main(String[] args) {
Callable callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int i = new Random().nextInt(5);
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return i;
}
};
?
/**
* callable創(chuàng)建futureTask
* FutureTask實(shí)現(xiàn)了RunnableFuture接口,因此即是Runnable又是Future
* 作為Runnable可以傳入Thread創(chuàng)建線程并執(zhí)行
* 作為Future,可以用來(lái)獲取執(zhí)行的結(jié)果。
* 這里創(chuàng)建出來(lái)的futureTask對(duì)象有人稱為"具柄"或者"存根",大家可以理解為用來(lái)獲取線程執(zhí)行結(jié)果的一個(gè)"引用"即可。
*/
FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
?
// 作為Runnable使用
Thread thread = new Thread(futureTask);
thread.start();
?
try {
// 作為Future使用
Integer integer = futureTask.get();
System.out.println(integer);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}因此FutureTask是Callable到Runnable的橋梁。
不使用Callable和Future,僅使用Runnable實(shí)現(xiàn)相同功能
下面我們看下,如果不使用Callable和Future,僅使用Runnable如何實(shí)現(xiàn)返回值。
public class TestMain {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread t1 = new Thread(myRunnable);
t1.start();
Object o = myRunnable.get();
System.out.println(o);
}
}
?
class MyRunnable implements Runnable {
// 存儲(chǔ)執(zhí)行結(jié)果
private Object outCome = null;
?
@Override
public void run() {
int i = new Random().nextInt(5);
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 存儲(chǔ)執(zhí)行結(jié)果
outCome = i;
// 產(chǎn)出結(jié)果后喚醒等待的get方法
synchronized (this) {
notifyAll();
}
}
?
public synchronized Object get() {
while(outCome == null) {
try {
// 等待產(chǎn)出結(jié)果
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return outCome;
}
}可以看出,通過(guò)Runnable實(shí)現(xiàn)更加麻煩,因此這也體現(xiàn)出了Callable+Future的優(yōu)勢(shì)。
以上就是詳解Java中Callable和Future的區(qū)別的詳細(xì)內(nèi)容,更多關(guān)于Java Callable Future區(qū)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Java使用多線程批次查詢大量數(shù)據(jù)(Callable返回?cái)?shù)據(jù))方式
- Java通過(guò)Callable實(shí)現(xiàn)多線程
- Java多線程中Callable和Future的解讀
- Java中的Callable實(shí)現(xiàn)多線程詳解
- Java使用Callable接口實(shí)現(xiàn)多線程的實(shí)例代碼
- Java多線程實(shí)現(xiàn)之Callable詳解
- Java中Runnable和Callable分別什么時(shí)候使用
- Java中Runnable與Callable接口的區(qū)別詳解
- Java使用Runnable和Callable實(shí)現(xiàn)多線程的區(qū)別詳解
- java面試常問(wèn)的Runnable和Callable的區(qū)別
- Java并發(fā)教程之Callable和Future接口詳解
- Java中callable的實(shí)現(xiàn)原理
相關(guān)文章
Java基于Javafaker生成測(cè)試數(shù)據(jù)
這篇文章主要介紹了Java基于Javafaker生成測(cè)試數(shù)據(jù)的方法,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-12-12
SpringBoot配置Actuator組件,實(shí)現(xiàn)系統(tǒng)監(jiān)控
在生產(chǎn)環(huán)境中,需要實(shí)時(shí)或定期監(jiān)控服務(wù)的可用性。Spring Boot的actuator(健康監(jiān)控)功能提供了很多監(jiān)控所需的接口,可以對(duì)應(yīng)用系統(tǒng)進(jìn)行配置查看、相關(guān)功能統(tǒng)計(jì)等。2021-06-06
Springboot-Starter造輪子之自動(dòng)鎖組件lock-starter實(shí)現(xiàn)
這篇文章主要為大家介紹了Springboot-Starter造輪子之自動(dòng)鎖組件lock-starter實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
Java實(shí)現(xiàn)企業(yè)微信消息推送功能的詳細(xì)步驟
這篇文章主要介紹了Java實(shí)現(xiàn)企業(yè)微信消息推送功能,本文圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
Netty學(xué)習(xí)教程之Netty與Marshalling結(jié)合發(fā)送對(duì)象
Netty是由JBOSS提供的一個(gè)Java開(kāi)源框架,之前已經(jīng)給大家簡(jiǎn)單介紹了一些基礎(chǔ)與使用,下面這篇文章主要給大家介紹了關(guān)于Netty與Marshalling結(jié)合發(fā)送對(duì)象的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-05-05
java 學(xué)習(xí)筆記(入門篇)_java的基礎(chǔ)語(yǔ)法
從基礎(chǔ)語(yǔ)法開(kāi)始,這個(gè)語(yǔ)法你也可以理解為英語(yǔ)或是漢語(yǔ)里面的語(yǔ)法,只不過(guò)大家各有各的特點(diǎn)和區(qū)別;那么在學(xué)習(xí)的過(guò)程中我們就要不斷的積累重要的類和方法,這樣寫程序就會(huì)方便快捷了,下面就開(kāi)始學(xué)習(xí)java的基礎(chǔ)語(yǔ)法2013-01-01
Java SpringSecurity+JWT實(shí)現(xiàn)登錄認(rèn)證
這篇文章主要介紹了Java SpringSecurity+JWT實(shí)現(xiàn)登錄認(rèn)證,首先通過(guò)給需要登錄認(rèn)證的模塊添加mall-security依賴展開(kāi)介紹,感興趣的朋友可以參考一下2022-06-06
MyBatisPlus中使用or()和and()遇到的問(wèn)題及細(xì)節(jié)處理
這篇文章主要介紹了MyBatisPlus中使用or()和and()遇到的問(wèn)題,本文通過(guò)多種寫法實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Java匿名內(nèi)部類導(dǎo)致內(nèi)存泄露的原因與解決方案詳解
這篇文章主要為大家詳細(xì)介紹了Java因?yàn)槟涿麅?nèi)部類導(dǎo)致內(nèi)存泄露的原因以及其解決方案,文中的示例代碼講解詳細(xì),希望對(duì)大家有所幫助2022-11-11

