異步第一篇:異步相關接口


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接口

 待研究

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM