# 牛年自強計畫 Week 5 - SpringBoot - 番外篇 Java 執行緒 FutureTask ## 【前言】 上篇介紹了 Future 這個可以協助開發者處理開出 Thread 取結果的類之後,接下來要介紹 Future 類的延伸 -- FutureTask 類。 ## 【FutureTask】 由於 Future 本身受限於 Interface,不能夠用來建立一個實體。 因此就有了 FutureTask 類,作為 Future 類的實體,同時也在 Callable 部分方法中扮演著重要角色。 FutureTask 繼承了 Runnable 和 Future,能夠視為一個獨立的 Runnable 類使用 Thread 方式直接執行,或放入 ExecuteService 執行。亦可當做一個 Future 類,處理包含檢測執行狀況、取得執行結果等等動作。 底下為 FutureTask 類架構圖: ![](https://i.imgur.com/pICnaXB.png) 最主要是作為整個 Callable 執行時的 Future 實體,並在有回傳結果的時候送返回去。 言簡意賅為: FutureTask 可以自己執行異步任務,同時可自行處理結果的取得。 ## 【屬性】 FutureTask 的核心屬性有五個: - state - callable - outcome - runner - waiters 其中 **state** 又有以下幾種設定值: | 數值 | 屬性 | 說明 | | ----- | ----- | ----- | | 0 | NEW | 新任務 | | 1 | COMPLETING | 執行中 | | 2 | NORMAL | 正常執行完畢 | | 3 | EXCEPTIONAL | 執行中報錯 | | 4 | CANCELLED | 任務取消 | | 5 | INTERRUPTING | 任務被取消中 | | 6 | INTERRUPTED | 任務被取消 | 可參考 ChiuCheng 的文章 [FutureTask源码解析(2)——深入理解FutureTask](https://segmentfault.com/a/1190000016572591) 有較詳細的解說。 ### 【範例】 **test.java** ```java= package Thread.FutureTask; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class test { private work work1, work2; private final workExecutorService workExecutorService = new workExecutorService(); @DisplayName("Test Future : All In, All Out.") @Test public void testCase1() throws ExecutionException, InterruptedException { work1 = new work("work_"+1, 6); work2 = new work("work_"+2, 2); FutureTask futureTask1 = new FutureTask(() -> { return work1.doWork(); }); FutureTask futureTask2 = new FutureTask(() -> { return work2.doWork(); }); workExecutorService.serviceAsync(futureTask1); workExecutorService.serviceAsync(futureTask2); System.out.println("Before Getting FutureTask Value."); System.out.println(futureTask1.get().toString()); System.out.println(futureTask2.get().toString()); System.out.println("After Getting FutureTask Value."); } @BeforeAll public static void BeforeAll(){ System.out.println("Test Start"); } @AfterAll public static void AfterAll(){ System.out.println("Test End"); } } ``` **work.java** ```java= package Thread.FutureTask; public class work { private String name; private int work_time; public work(String name, int work_time){ this.name = name; this.work_time = work_time; } public String doWork(){ int totalWorkTime = (int)(1000*this.work_time); System.out.println(name + " start and it needs : " +totalWorkTime + " secs to finish."); try { Thread.sleep(totalWorkTime); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + " done."); return "After " + totalWorkTime + " secs, " + name + " done."; } } ``` **workExecutorService.java** ```java= package Thread.FutureTask; import Thread.Future.work; import java.util.concurrent.*; public class workExecutorService { private final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 60L, TimeUnit.SECONDS,new ArrayBlockingQueue(3)); public void serviceAsync(FutureTask futureTask){ threadPoolExecutor.submit(futureTask); } public boolean isFinish(){ return threadPoolExecutor.getActiveCount() <= 0; } public void doShutdown(){ threadPoolExecutor.shutdown(); try { if(!threadPoolExecutor.awaitTermination(5000, TimeUnit.SECONDS)) return; } catch (InterruptedException e) { e.printStackTrace(); } while(!threadPoolExecutor.isTerminated() || threadPoolExecutor.isTerminating()){ System.out.println("Is terminating."); } System.out.println("Is terminated."); } } ``` ### 【範例結果】 從程式中可以看到,在最後呈現結果的前後各加了一句確認句,這是為了讓大家理解使用 FutureTask 在異步任務中的處理時程。 且同上一篇提到的,FutureTask 的 get() 不為異步任務,因此具有程式執行阻塞性,可以看到執行過程中,futureTask2 已經執行完畢了,但程式停在 futureTask1.get(),直到取得 futureTask1.get() 執行完畢,futureTask2.get() 才會繼續執行。 ```bash Test Start Before Getting FutureTask Value. work_1 start and it needs : 6000 secs to finish. work_2 start and it needs : 2000 secs to finish. work_2 done. work_1 done. After 6000 secs, work_1 done. After 2000 secs, work_2 done. After Getting FutureTask Value. Test End ``` 首頁 [Kai 個人技術 Hackmd](/2G-RoB0QTrKzkftH2uLueA) ###### tags: `Spring Boot`