Future接口
Future表示一個異步計算任務的結果。
Future接口方法有:
boolean cancel(boolean mayInterruptIfRunning):取消異步運算。入參為true時,表示會取消已經開始執行的運算。為false時,不會取消已經開始執行的運算。
boolean isCancelled():
boolean isDone():任務結束的話,返回true,否則返回false。任務結束不僅僅指任務順利完成,還包括任務拋異常、任務被取消等。
V get() throws InterruptedException, ExecutionException:在主線程中獲取異步運算的結果,在獲取到結果之前主線程一直阻塞。如果任務執行拋異常,則get()方法會拋出ExecutionException異常。如果任務被取消,則get()會拋出CancellationException異常。
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException:在主線程中獲取異步運算的結果,在獲取到結果之前主線程阻塞,超過指定時間后會拋出TimeoutException異常。
RunnableFuture接口
RunnableFuture接口繼承了Runnable接口和Future接口,但並未定義自己的方法。
FutureTask是RunnableFuture實現類。FutureTask有兩個構造器:FutureTask(Callable<V> callable)和FutureTask(Runnable runnable, V result)。
TODO示例
FutureTask的run()實例方法內部是調用Runnable實例或者Callable實例的run()方法,但是是在主線程執行,而不是在異步線程執行。這j8有啥用???
ListenableFuture接口
其實ListenableFuture接口有兩個,但都不是jdk自帶的,guava一個,spring一個。
guava的ListenableFuture接口全類名是com.google.common.util.concurrent.ListenableFuture,繼承了Future接口,只定義了一個方法:void addListener(Runnable listener, Executor executor)。常用實現類是guava的ListenableFutureTask類,全類名是com.google.common.util.concurrent.ListenableFutureTask。
spring的ListenableFuture接口在spring-core.jar包中,全類名是org.springframework.util.concurrent.ListenableFuture,繼承了Future接口,定義方法如下:
void addCallback(ListenableFutureCallback<T> callback):注冊一個ListenableFutureCallback實例。
void addCallback(SuccessCallback<T> successCallback, FailureCallback failureCallback):注冊一個SuccessCallback實例和一個failureCallback實例。
completableFuture<T> completable():把一個spring的ListenableFuture實例轉成一個jdk的CompletableFuture實例。
spring的ListenableFuture接口常用實現類是spring的ListenableFutureTask和AsyncResult。
guava ListenableFutureTask使用示例:
public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); ListeningExecutorService service = MoreExecutors.listeningDecorator(executorService); long begin = System.currentTimeMillis(); ListenableFuture<Boolean> booleanTask = service.submit(() -> { Thread.sleep(1000); System.out.println("1, currentThread= " + Thread.currentThread().getName()); System.out.println("".substring(0, 1)); return true; }); booleanTask.addListener(() -> { try { booleanTask.get(); Thread.sleep(2000); System.out.println("2, currentThread= " + Thread.currentThread().getName()); } catch (Exception e) { System.out.println(123); // e.printStackTrace(); } }, executorService); Futures.addCallback(booleanTask, new FutureCallback<Boolean>() { @Override public void onSuccess(Boolean result) { System.out.println("3, currentThread= " + Thread.currentThread().getName() + ", booleanTask result= " + result); } @Override public void onFailure(Throwable e) { System.out.println(234); // e.printStackTrace(); } }, executorService); System.out.println("cost " + (System.currentTimeMillis() - begin) + "ms"); }
利用guava的MoreExecutors工具類構造出ListeningExecutorService實例,調用此實例的submit()方法即可得到一個ListenableFuture實例。接下來可以調用ListenableFuture的addListener(Runnable listener, Executor executor)方法添加一個監聽任務,但這個方法說實話,不好。為什么呢?因為addListener()方法添加的監聽任務不管被監聽任務是否拋異常都會執行,要是想不拋異常執行一個任務,拋異常時執行另一個任務,就要用try catch把ListenableFuture實例的get()方法包裹,然后在try子句中寫不拋異常時要執行的任務,catch子句中寫拋異常時要執行的任務。不如用guava提供的Futures工具類,這個工具類中提供了很多靜態方法,其中addCallback(ListenableFuture<V> future, FutureCallback<V> callback, Executor executor)方法可以輕松實現ListenableFuture任務拋異常和不拋異常時監聽任務的不同分支。
FluentFuture類
FluentFuture是guava提供的類,在com.google.common.util.concurrent包中,全類名是com.google.common.util.concurrent.FluentFuture。
待研究
spring ListenableFutureTask使用示例:
TODO示例
AsyncResult類
AsyncResult是spring提供的類,在spring-context.jar包中,全類名是org.springframework.scheduling.annotation.AsyncResult。AsyncResult實現了ListenableFuture接口。
AsyncResult使用示例:
public static void main(String[] args) throws NoSuchAlgorithmException { AsyncResult<Number> asyncResult = new AsyncResult<>(getRandom()); asyncResult.addCallback(result -> { System.out.println("result= " + result + ", currentThread= " + Thread.currentThread().getName()); }, e -> { System.out.println("e= " + e.getMessage() + ", currentThread= " + Thread.currentThread().getName()); } ); } private static Double getRandom() throws NoSuchAlgorithmException { SecureRandom secureRandom = SecureRandom.getInstanceStrong(); return secureRandom.nextDouble(); }
這下終於按照預期打印了。
CompletableFuture接口
待研究
