java Callable接口和Future接口創(chuàng)建線程示例詳解
Callable接口和Future接口
創(chuàng)建線程的方式
1.繼承Thread類2.實現(xiàn)Runnable接口3.Callable接口4.線程池方式
Callable接口
在繼承Thread類和實現(xiàn)Runnable接口的方式創(chuàng)建線程時,線程執(zhí)行的run方法中,返回值是void,即無法返回線程的執(zhí)行結(jié)果,為了支持該功能,java提供了Callable接口。
Callable和Runnable接口的區(qū)別
- 1.Callable中的call()方法,可以返回值,Runnable接口中的run方法,無返回值(void)。
- 2.call()方法可以拋出異常,run()不能拋異常。
- 3.實現(xiàn)Callable接口,必須重寫call()方法,run是抽象方法,抽象類可以不實現(xiàn)。
- 4.不能用Callable接口的對象,直接替換Runnable接口對象,創(chuàng)建線程。
Future接口
當call()方法完成時,結(jié)果必須存儲在主線程已知的對象中,以便主線程可以知道線程返回的結(jié)果,可以使用Future對象。將Future視為保存結(jié)果的對象-該對象,不一定會將call接口返回值,保存到主線程中,但是會持有call返回值。Future基本上是主線程可以跟蹤以及其他線程的結(jié)果的一種方式。要實現(xiàn)此接口,必須重寫5個方法。
public interface Future<V> {//Future源碼 /** * 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); //用于停止任務(wù),如果未啟動,將停止任務(wù),已啟動,僅在mayInterrupt為true時才會中斷任務(wù) /** * 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();//判斷任務(wù)是否完成,完成true,未完成false /** * 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;//任務(wù)完成返回結(jié)果,未完成,等待完成 /** * 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; }
Callable和Future是分別做各自的事情,Callable和Runnable類似,因為它封裝了要在另一個線程上允許的任務(wù),而Future用于存儲從另一個線程獲取的結(jié)果。實際上,F(xiàn)uture和Runnable可以一起使用。創(chuàng)建線程需要Runnable,為了獲取結(jié)果,需要Future。
FutureTask
Java庫本身提供了具體的FutureTask類,該類實現(xiàn)了Runnable和Future接口,并方便的將兩種功能組合在一起。并且其構(gòu)造函數(shù)提供了Callable來創(chuàng)建FutureTask對象。然后將該FutureTask對象提供給Thread的構(gòu)造函數(shù)以創(chuàng)建Thread對象。因此,間接的使用Callable創(chuàng)建線程。
關(guān)于FutureTask構(gòu)造函數(shù)的理解
public class FutureTask<V> implements RunnableFuture<V> {//實現(xiàn)了RunnableFuture //該類的構(gòu)造函數(shù)有兩個 public FutureTask(Callable<V> callable) {// if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable } //用此方法創(chuàng)建的線程,最后start()調(diào)用的其實是Executors.RunnableAdapter類的call(); public FutureTask(Runnable runnable, V result) {//返回的結(jié)果,就是構(gòu)造函數(shù)傳入的值 this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable } //原因如下 //使用FutureTask對象的方式,創(chuàng)建的Thread,在開啟線程.start后,底層執(zhí)行的是 //Thread的方法 start()方法會調(diào)用start0(),但是調(diào)用這個start0()(操作系統(tǒng)創(chuàng)建線程)的時機,是操作系統(tǒng)決定的,但是這個start0()最后會調(diào)用run()方法,此線程的執(zhí)行內(nèi)容就在傳入的對象的run()方法中 public void run() { if (target != null) { target.run(); //執(zhí)行到這 target就是在創(chuàng)建Thread時,傳遞的Runnable接口的子類對象,F(xiàn)UtureTask方式就是傳入的FutureTask對象 //會執(zhí)行FutureTask中的run()方法 } } //FutureTask的run() public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable;//類的屬性 if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); //會執(zhí)行callable的call(),callable是創(chuàng)建TutureTask時,根據(jù)傳入的Runnable的對象封裝后的一個對象 //this.callable = Executors.callable(runnable, result); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } } //Executors類的callable public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result); } //最后執(zhí)行到這里 Executors類的靜態(tài)內(nèi)部類RunnableAdapter static final class RunnableAdapter<T> implements Callable<T> { final Runnable task; final T result; RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result; } public T call() { task.run(); return result; } } } public interface RunnableFuture<V> extends Runnable, Future<V> {//繼承了Runnable, Future<V>接口 void run();// }
使用FutureTask類間接的用Callable接口創(chuàng)建線程
/** * @author 長名06 * @version 1.0 * 演示Callable創(chuàng)建線程 需要使用到Runnable的實現(xiàn)類FutureTask類 */ public class CallableDemo { public static void main(String[] args) { FutureTask<Integer> futureTask = new FutureTask<>(() -> { System.out.println(Thread.currentThread().getName() + "使用Callable接口創(chuàng)建的線程"); return 100; }); new Thread(futureTask,"線程1").start(); } }
核心原理
在主線程中需要執(zhí)行耗時的操作時,但不想阻塞主線程,可以把這些作業(yè)交給Future對象來做。
- 1.主線程需要,可以通過Future對象獲取后臺作業(yè)的計算結(jié)果或者執(zhí)行狀態(tài)。
- 2.一般FutureTask多用于耗時的計算,主線程可以在完成自己的任務(wù)后,再獲取結(jié)果。
- 3.只有執(zhí)行完后,才能獲取結(jié)果,否則會阻塞get()方法。
- 4.一旦執(zhí)行完后,不能重新開始或取消計算。get()只會計算一次
小結(jié)
- 1.在主線程需要執(zhí)行比較耗時的操作時,但又不想阻塞主線程,可以把這些作業(yè)交給Future對象在后臺完成,當主線程將來需要時,就可以通過Future對象獲得后臺作業(yè)的計算結(jié)果或者執(zhí)行狀態(tài)。
- 2.一般FutureTask多用于耗時的計算,主線程可以在完成自己的任務(wù)后,再去獲取結(jié)果。
- 3.get()方法只能獲取結(jié)果,并且只能計算完后獲取,否則會一直阻塞直到任務(wù)轉(zhuǎn)入完成狀態(tài),然后會返回結(jié)果或拋出異常。且只計算一次,計算完成不能重新開始或取消計算。
以上就是java Callable接口和Future接口創(chuàng)建線程示例詳解的詳細內(nèi)容,更多關(guān)于java Callable Future接口創(chuàng)建線程的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot使用dubbo和zookeeper代碼實例
這篇文章主要介紹了springboot使用dubbo和zookeeper代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11Java形參和實參的實例之Integer類型與Int類型用法說明
這篇文章主要介紹了Java形參和實參的實例之Integer類型與Int類型用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10