Future 是Java原生API中JUC包下提供的接口。JUC是Java用來處理併發內容的集合,簡單來說Future就是用來處理在同步執行代碼中獲取異步執行結果的上層接口,其下有多種實現類用於不同併發場景。
原生Future中的get()方法,會阻塞當前線程,知道Future中執行的異步任務完成後。Netty在原生基礎上又增加了監聽器(Listener)接口,用來更精確的控制異步任務執行時間。
Future常用實現類
FutureTask
- 主要繼承關係:實現Runnable接口和Future接口
- 主要功能:可以被看作Runnable對象提交線程池執行,可以看作Future對象獲取異步執行結果
簡單使用示例
package com.ht.actuatorlearn.curr.future;
import java.util.concurrent.*;
/**
* FutureTask 類示例
* 線程池異步執行任務,在同步代碼塊中阻塞獲取異步執行結果
*
* @author: lht
* @date: 2023-03-02
*/
public class FutureTaskTest {
/**
* 聲明線程池
*/
private static ExecutorService EXECUTOR = null;
public static void main(String[] args) {
EXECUTOR = Executors.newSingleThreadExecutor();
// 創建異步執行Future對象
FutureTask<String> futureTask = new FutureTask<>(() -> {
// 注意這裏使用的 Callable 類異步執行
// 休眠5s 代替耗時操作
TimeUnit.SECONDS.sleep(5);
return "hello";
});
try {
// 提交執行任務
EXECUTOR.execute(futureTask);
// 同步代碼塊1
System.out.println("Waiting async Results....");
// 獲取異步執行結果 線程阻塞
System.out.println("Result is: " + futureTask.get());
// 同步代碼塊2
System.out.println("Completed...");
EXECUTOR.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
ScheduledFuture
- 主要功能:用於獲取在程序中計劃定期執行任務的結果
簡單使用示例
package com.ht.actuatorlearn.curr.future;
import java.util.concurrent.*;
/**
* 延遲執行任務,並在接收到特定結果下執行一系列操作(關閉任務)
*
* @author: lht
* @date: 2023-03-03
*/
public class ScheduledFutureTest {
public static void main(String[] args) {
// 聲明工作線程池
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
// 創建隨機數任務
Callable<Integer> task = () -> {
return (int) (Math.random() * 10);
};
// 延時任務提交線程池
ScheduledFuture<Integer> schedule = executorService.schedule(task, 5, TimeUnit.SECONDS);
try {
Integer result = schedule.get();
System.out.println("Task Result: " + result);
// 關閉線程池
executorService.shutdown();
}catch (Exception e) {
e.printStackTrace();
}
}
}
ChannelFuture
Netty中,ChannelFuture類似於Future,表示異步的I/O操作結果。當創建新通道或使用Channel進行發送或接收數據時,這些耗時操作在Netty的底層都是異步進行處理的。如果實際業務邏輯中需要獲取上述異步的執行結果,那就需要使用到ChannelFuture.
常用示例
- 添加監聽器(最常用處理):ChannelFuture基於Future的阻塞模型上又實現了監聽器回調模式,可以更精確的獲取異步執行結果和操作信息,並且不阻塞主線程
Object message = new Object();
// channel 異步發送數據
ChannelFuture future = ctx.writeAndFlush(message);
future.addListener((ChannelFutureListener) channelFuture -> {
if (future.isSuccess()) {
// 消息發送成功 回調
} else {
// 消息發送失敗 回調
}
});
2.同步等待操作完成:使用sync()方法可以時耗時異步動作變爲同步動作,同步等待耗時操作完成再執行後續代碼
// 同步推送數據
ChannelFuture channelFuture = ctx.writeAndFlush(message).sync();
System.out.println(channelFuture.isSuccess());
3.異步等待: 使用ChannelFuture 的 await() 異步等待I/O動作完成,等待中將阻塞當前線程,只到操作完成或中斷
// 阻塞當前線程 異步等待
ChannelFuture channelFuture = ctx.writeAndFlush(message).await();
System.out.println(channelFuture.isSuccess());
實際上:從ChannelFuture的源碼中我們可以看到,它其實是Future的拓展,並且不具有返回值的異步調用,同時和一個Channel進行綁定。ChannelPromise接口又在其上繼承了ChannelFuture類和Promise類,使之既可以寫異步執行結果,又具備監聽通道的功能。