# 牛年自強計畫 Week 5 - SpringBoot - 番外篇 Java 執行緒 FutureTask
## 【前言】
上篇介紹了 Future 這個可以協助開發者處理開出 Thread 取結果的類之後,接下來要介紹 Future 類的延伸 -- FutureTask 類。
## 【FutureTask】
由於 Future 本身受限於 Interface,不能夠用來建立一個實體。
因此就有了 FutureTask 類,作為 Future 類的實體,同時也在 Callable 部分方法中扮演著重要角色。
FutureTask 繼承了 Runnable 和 Future,能夠視為一個獨立的 Runnable 類使用 Thread 方式直接執行,或放入 ExecuteService 執行。亦可當做一個 Future 類,處理包含檢測執行狀況、取得執行結果等等動作。
底下為 FutureTask 類架構圖:

最主要是作為整個 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`