業(yè)精于勤,荒于嬉;行成于思,毀于隨?!n愈
它告訴我們,事業(yè)的成功在于奮發(fā)努力,勤勉進取,太貪玩,放松要求便會一事無成;做事情要想成功,需要反復(fù)思考、深思熟慮,而隨手隨意、隨隨便便行事,做事不經(jīng)過大腦,必然招致失敗。
PS: 如果覺得本文有用的話,請幫忙點贊,留言評論支持一下哦,您的支持是我最大的動力!謝謝啦~
FutureTask 也可以做閉鎖,它是 Future 和 callable 的結(jié)合體。所以我們有必要來了解 FutureTask 這個類。
FutureTask 的繼承關(guān)系類圖
先看 FutureTask 類的繼承:
public class FutureTask<V> implements RunnableFuture<V>
它繼承自 RunnableFuture,可以看出他是 Runnable 和 Future 的結(jié)合體。
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
我們熟悉的 Runnable 接口:
public interface Runnable {
public abstract void run();
}
不常見的Future 接口,用來獲取異步計算結(jié)果:
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.
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* Returns {@code true} if this task was cancelled before it completed
* normally.
*/
boolean isCancelled();//如果任務(wù)被取消,返回true
/**
* Returns {@code true} if this task completed.
*/
boolean isDone();//如果任務(wù)執(zhí)行結(jié)束,無論是正常結(jié)束或是中途取消還是發(fā)生異常,都返回true。
/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*/
V get() throws InterruptedException, ExecutionException; //獲取異步執(zhí)行的結(jié)果,如果沒有結(jié)果可用,此方法會阻塞直到異步計算完成。
/**
* Waits if necessary for at most the given time for the computation
* to complete, and then retrieves its result, if available.
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
到這里,F(xiàn)utureTask 整個繼承關(guān)系已經(jīng)很清楚了。為了更直觀一點,我用 starUML 畫出它的類繼承關(guān)系圖。
在類關(guān)系圖中,我們可以看到 FutureTask 的構(gòu)造函數(shù),包含了之前沒有見過的類型:Callable<T>。我們直接看下它的兩個構(gòu)造函數(shù)實現(xiàn),進一步了解看看:
//構(gòu)造函數(shù)1
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
//構(gòu)造函數(shù)2
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
這里已經(jīng)非常清楚了,最終都是賦值給 FutureTask 的內(nèi)部變量 callable。它是一個接口,包含一個有返回值的函數(shù) call()。
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
通過上面的講解,我們已經(jīng)知道 Future,FutureTask,Callable,Runnable的關(guān)系了。那么,說了這么多主要是想干嘛呢?
沒錯,主要就是為了線程執(zhí)行完成后能夠返回結(jié)果。我們知道,Runnable 接口執(zhí)行完成后,是沒法返回結(jié)果的。所以,我們?nèi)绻胍軌蚍祷貓?zhí)行的結(jié)果,必須使用 callable 接口。
應(yīng)用場景
比如我們有個耗時的計算操作,現(xiàn)在創(chuàng)建一個子線程執(zhí)行計算操作,主線程通過 FutureTask.get() 的方式獲取計算結(jié)果,如果計算還沒有完成,則會阻塞一直等到計算完成。
下面我們直接編寫代碼來實現(xiàn)上面的應(yīng)用場景。
使用 Callable + FutureTask 獲取執(zhí)行結(jié)果:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutureTaskTest{
//創(chuàng)建一個Future對象,并把Callable的實現(xiàn)傳給構(gòu)造函數(shù)
private static final FutureTask<Integer> future = new FutureTask<Integer>(new CallableTest());
public static void main(String[] args) {
//創(chuàng)建一個線程
final Thread thread = new Thread(future);
//啟動線程
thread.start();
try {
Thread.sleep(1000);
System.out.println("Main thread is running");
//獲取計算結(jié)果,會阻塞知道計算完畢
System.out.println("get the sub thread compute result : " + future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main thread is end");
}
//實現(xiàn)Callable接口,耗時操作
static class CallableTest implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int ret = 0;
Thread.sleep(1000);
System.out.println("sub thread is computing");
for(int i = 0; i < 1000; i++) {
ret += i;
}
System.out.println("sub thread is finish compute");
return ret;
}
}
}
運行結(jié)果:
另外一種方式,是使用 Callable + Future + ExecutorService 的方式。ExecutorService繼承自Executor,它的目的是為我們管理Thread對象,從而簡化并發(fā)編程,Executor使我們無需顯示的去管理線程的生命周期。
在ExecutorService接口中聲明了若干個submit方法的重載版本:
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
第一個submit方法里面的參數(shù)類型就是Callable。
示例如下:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
public class FutureTaskTest{
public static void main(String[] args) {
//返回一個線程池,通常都和這種線程寬架搭配
ExecutorService threadPool = Executors.newSingleThreadExecutor();
System.out.println("Main thread is running");
//提交給線程,返回一個Future類,并執(zhí)行
Future<Integer> future = threadPool.submit(new CallableTest());
try {
Thread.sleep(1000);
//獲取計算結(jié)果,會阻塞知道計算完畢
System.out.println("get the sub thread compute result : " + future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main thread is end");
}
//實現(xiàn)Callable接口,耗時操作
static class CallableTest implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int ret = 0;
Thread.sleep(1000);
System.out.println("sub thread is computing");
for(int i = 0; i < 1000; i++) {
ret += i;
}
System.out.println("sub thread is finish compute");
return ret;
}
}
}
執(zhí)行結(jié)果
本文完結(jié),希望看完對你有幫助,歡迎關(guān)注我~