并发编程-21J.U.C组件拓展之Future和FutureTask
文章目錄
- 概述
- FutureTask的三種運行狀態
- FutureTask的三種運行狀態下的get/cancel操作及結果
- FutureTask的實現
- FutureTask的使用
- 示例
- Future
- FutureTask
- 代碼
概述
Future接口和實現Future接口的FutureTask類,代表異步計算的結果。
FutureTask除了實現Future接口外,還實現了Runnable接口。因此,FutureTask可以交給Executor執行,也可以由調用線程直接執行(FutureTask.run())。
FutureTask的三種運行狀態
根據FutureTask.run()方法被執行的時機,FutureTask可以處于下面3種狀態
- 未啟動。FutureTask.run()方法還沒有被執行之前,FutureTask處于未啟動狀態。當創建一個FutureTask,且沒有執行FutureTask.run()方法之前,這個FutureTask處于未啟動狀態。
- 已啟動。FutureTask.run()方法被執行的過程中,FutureTask處于已啟動狀態。
- 已完成。FutureTask.run()方法執行完后正常結束,或被取消(FutureTask.cancel(…)),或執行FutureTask.run()方法時拋出異常而異常結束,FutureTask處于已完成狀態。
FutureTask的三種運行狀態下的get/cancel操作及結果
-
當FutureTask處于未啟動或已啟動狀態時,執行FutureTask.get()方法將導致調用線程阻塞
-
當FutureTask處于已完成狀態時,執行FutureTask.get()方法將導致調用線程立即返回結果或拋出異常
-
當FutureTask處于未啟動狀態時,執行FutureTask.cancel()方法將導致此任務永遠不會被執行
-
當FutureTask處于已啟動狀態時,執行FutureTask.cancel(true)方法將以中斷執行此任務線程的方式來試圖停止任務
-
當FutureTask處于已啟動狀態時,執行FutureTask.cancel(false)方法將不會對正在執行此任務的線程產生影響(讓正在執行的任務運行完成)
-
當FutureTask處于已完成狀態時,執行FutureTask.cancel(…)方法將返回false。
FutureTask的實現
FutureTask的實現基于AbstractQueuedSynchronizer(AQS)。
AQS是一個同步框架,它提供通用機制來原子性管理同步狀態、阻塞和喚醒線程,以及維護被阻塞線程的隊列。
基于AQS實現的同步器包括:ReentrantLock、Semaphore、ReentrantReadWriteLock、CountDownLatch和FutureTask
并發編程-15并發容器(J.U.C)核心 AbstractQueuedSynchronizer 抽象隊列同步器AQS介紹
每一個基于AQS實現的同步器都會包含兩種類型的操作
-
至少一個acquire操作。這個操作阻塞調用線程,除非/直到AQS的狀態允許這個線程繼續執行。FutureTask的acquire操作為get()/get(long timeout,TimeUnit unit)方法調用
-
至少一個release操作。這個操作改變AQS的狀態,改變后的狀態可允許一個或多個阻塞線程被解除阻塞。FutureTask的release操作包括run()方法和cancel(…)方法
基于“復合優先于繼承”的原則,FutureTask聲明了一個內部私有的繼承于AQS的子類Sync,對FutureTask所有公有方法的調用都會委托給這個內部子類
AQS被作為“模板方法模式”的基礎類提供給FutureTask的內部子類Sync,這個內部子類只需要實現狀態檢查和狀態更新的方法即可,這些方法將控制FutureTask的獲取和釋放操作。具體來說,Sync實現了AQS的tryAcquireShared(int)方法和tryReleaseShared(int)方法,Sync通過這兩個方法來檢查和更新同步狀態。
FutureTask的使用
-
可以把FutureTask交給Executor執行
-
也可以通過ExecutorService.submit(…)方法返回一個FutureTask,然后執行FutureTask.get()方法或FutureTask.cancel(…)方法
-
除此以外,還可以單獨使用FutureTask
當一個線程需要等待另一個線程把某個任務執行完后它才能繼續執行,此時可以使用FutureTask.
示例
Future
package com.artisan.example.aqs;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;@Slf4j public class FutureExample {static class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {// 耗時任務log.info("do something in callable start");Thread.sleep(5000);log.info("do something in callable end");return "DONE";}}public static void main(String[] args) throws Exception {// 創建一個newCachedThreadPool線程池ExecutorService executorService = Executors.newCachedThreadPool();// submit任務Future<String> future = executorService.submit(new MyCallable());// 主線程模擬一些業務操作,假設耗時一秒log.info("do something in main begin");Thread.sleep(1000);log.info("do something in main finish");// 獲取剛才提交的線程MyCallable的返回結果log.info("獲取MyCallable的返回結果,如果未返回,主線程將阻塞,處于等待狀態");String result = future.get();log.info("result:{}", result);// 關閉線程池executorService.shutdown();} }觀察執行結果:
FutureTask
package com.artisan.example.aqs;import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask;import lombok.extern.slf4j.Slf4j;@Slf4j public class FutureTaskExample {public static void main(String[] args) throws Exception {FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {@Overridepublic String call() throws Exception {// 耗時任務log.info("do something in callable");Thread.sleep(5000);return "DONE";}});//創建一個newCachedThreadPool線程池ExecutorService executorService = Executors.newCachedThreadPool();// execute futureTask任務executorService.execute(futureTask);// 主線程模擬一些業務操作,假設耗時一秒log.info("do something in main begin");Thread.sleep(1000);log.info("do something in main finish");// 獲取剛才提交的線程MyCallable的返回結果log.info("獲取futureTask的返回結果,如果未返回,主線程將阻塞,處于等待狀態");String result = futureTask.get();log.info("result:{}", result);// 關閉線程池executorService.shutdown();} }代碼
https://github.com/yangshangwei/ConcurrencyMaster
總結
以上是生活随笔為你收集整理的并发编程-21J.U.C组件拓展之Future和FutureTask的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 并发编程-19AQS同步组件之重入锁Re
- 下一篇: 并发编程-22J.U.C组件拓展之For