Java多線程編程:Callable、Future和FutureTask淺析
阿新 • • 發佈:2017-05-17
創建線程 執行 過程 data- body javase 接下來 而後 定義 view plain copy
print?
[java] view plain copy
print?
view plain copy
print?
下面我們再來看看FutureTask的方法執行示意圖(方法和Future接口基本是一樣的,這裏就不過多描述了)
分析: (1)當FutureTask處於未啟動或已啟動狀態時,如果此時我們執行FutureTask.get()方法將導致調用線程阻塞;當FutureTask處於已完成狀態時,執行FutureTask.get()方法將導致調用線程立即返回結果或者拋出異常。 (2)當FutureTask處於未啟動狀態時,執行FutureTask.cancel()方法將導致此任務永遠不會執行。 當FutureTask處於已啟動狀態時,執行cancel(true)方法將以中斷執行此任務線程的方式來試圖停止任務,如果任務取消成功,cancel(...)返回true;但如果執行cancel(false)方法將不會對正在執行的任務線程產生影響(讓線程正常執行到完成),此時cancel(...)返回false。 當任務已經完成,執行cancel(...)方法將返回false。 最後我們給出FutureTask的兩種構造函數: [java] view plain copy print?
3.2 使用Callable+FutureTask獲取執行結果
[java] view plain copy
print?
通過前面幾篇的學習,我們知道創建線程的方式有兩種,一種是實現Runnable接口,另一種是繼承Thread,但是這兩種方式都有個缺點,那就是在任務執行完成之後無法獲取返回結果,那如果我們想要獲取返回結果該如何實現呢?還記上一篇Executor框架結構中提到的Callable接口和Future接口嗎?,是的,從Java SE 5.0開始引入了Callable和Future,通過它們構建的線程,在任務執行完成後就可以獲取執行結果,今天我們就來聊聊線程創建的第三種方式,那就是實現Callable接口。
1.Callable<V>接口 我們先回顧一下java.lang.Runnable接口,就聲明了run(),其返回值為void,當然就無法獲取結果了。 [java]
- public interface Runnable {
- public abstract void run();
- }
而Callable的接口定義如下
[java] view plain copy print?- public interface Callable<V> {
- V call() throws Exception;
- }
該接口聲明了一個名稱為call()的方法,同時這個方法可以有返回值V,也可以拋出異常。嗯,對該接口我們先了解這麽多就行,下面我們來說明如何使用,前篇文章我們說過,無論是Runnable接口的實現類還是Callable接口的實現類,都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor執行,ThreadPoolExecutor或ScheduledThreadPoolExecutor都實現了ExcutorService接口,而因此Callable需要和Executor框架中的ExcutorService結合使用,我們先看看ExecutorService提供的方法:
- <T> Future<T> submit(Callable<T> task);
- <T> Future<T> submit(Runnable task, T result);
- Future<?> submit(Runnable task);
- public static Callable<Object> callable(Runnable task)
- public static <T> Callable<T> callable(Runnable task, T result)
- public interface Future<V> {
- boolean cancel(boolean mayInterruptIfRunning);
- boolean isCancelled();
- boolean isDone();
- V get() throws InterruptedException, ExecutionException;
- V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
- }
- public class FutureTask<V> implements RunnableFuture<V> {
- public interface RunnableFuture<V> extends Runnable, Future<V> {
- void run();
- }
下面我們再來看看FutureTask的方法執行示意圖(方法和Future接口基本是一樣的,這裏就不過多描述了)
分析: (1)當FutureTask處於未啟動或已啟動狀態時,如果此時我們執行FutureTask.get()方法將導致調用線程阻塞;當FutureTask處於已完成狀態時,執行FutureTask.get()方法將導致調用線程立即返回結果或者拋出異常。 (2)當FutureTask處於未啟動狀態時,執行FutureTask.cancel()方法將導致此任務永遠不會執行。 當FutureTask處於已啟動狀態時,執行cancel(true)方法將以中斷執行此任務線程的方式來試圖停止任務,如果任務取消成功,cancel(...)返回true;但如果執行cancel(false)方法將不會對正在執行的任務線程產生影響(讓線程正常執行到完成),此時cancel(...)返回false。 當任務已經完成,執行cancel(...)方法將返回false。 最後我們給出FutureTask的兩種構造函數: [java] view plain copy print?
- public FutureTask(Callable<V> callable) {
- }
- public FutureTask(Runnable runnable, V result) {
- }
- package com.zejian.Executor;
- import java.util.concurrent.Callable;
- /**
- * @author zejian
- * @time 2016年3月15日 下午2:02:42
- * @decrition Callable接口實例
- */
- public class CallableDemo implements Callable<Integer> {
- private int sum;
- @Override
- public Integer call() throws Exception {
- System.out.println("Callable子線程開始計算啦!");
- Thread.sleep(2000);
- for(int i=0 ;i<5000;i++){
- sum=sum+i;
- }
- System.out.println("Callable子線程計算結束!");
- return sum;
- }
- }
Callable執行測試類如下:
[java] view plain copy print?
- package com.zejian.Executor;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
- /**
- * @author zejian
- * @time 2016年3月15日 下午2:05:43
- * @decrition callable執行測試類
- */
- public class CallableTest {
- public static void main(String[] args) {
- //創建線程池
- ExecutorService es = Executors.newSingleThreadExecutor();
- //創建Callable對象任務
- CallableDemo calTask=new CallableDemo();
- //提交任務並獲取執行結果
- Future<Integer> future =es.submit(calTask);
- //關閉線程池
- es.shutdown();
- try {
- Thread.sleep(2000);
- System.out.println("主線程在執行其他任務");
- if(future.get()!=null){
- //輸出獲取到的結果
- System.out.println("future.get()-->"+future.get());
- }else{
- //輸出獲取到的結果
- System.out.println("future.get()未獲取到結果");
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("主線程在執行完成");
- }
- }
執行結果:
Callable子線程開始計算啦! 主線程在執行其他任務 Callable子線程計算結束! future.get()-->12497500 主線程在執行完成 |
- package com.zejian.Executor;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
- import java.util.concurrent.FutureTask;
- /**
- * @author zejian
- * @time 2016年3月15日 下午2:05:43
- * @decrition callable執行測試類
- */
- public class CallableTest {
- public static void main(String[] args) {
- // //創建線程池
- // ExecutorService es = Executors.newSingleThreadExecutor();
- // //創建Callable對象任務
- // CallableDemo calTask=new CallableDemo();
- // //提交任務並獲取執行結果
- // Future<Integer> future =es.submit(calTask);
- // //關閉線程池
- // es.shutdown();
- //創建線程池
- ExecutorService es = Executors.newSingleThreadExecutor();
- //創建Callable對象任務
- CallableDemo calTask=new CallableDemo();
- //創建FutureTask
- FutureTask<Integer> futureTask=new FutureTask<>(calTask);
- //執行任務
- es.submit(futureTask);
- //關閉線程池
- es.shutdown();
- try {
- Thread.sleep(2000);
- System.out.println("主線程在執行其他任務");
- if(futureTask.get()!=null){
- //輸出獲取到的結果
- System.out.println("futureTask.get()-->"+futureTask.get());
- }else{
- //輸出獲取到的結果
- System.out.println("futureTask.get()未獲取到結果");
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("主線程在執行完成");
- }
- }
Callable子線程開始計算啦! 主線程在執行其他任務 Callable子線程計算結束! futureTask.get()-->12497500 主線程在執行完成 |
Java多線程編程:Callable、Future和FutureTask淺析