Future 與 ChannelFuture 異步處理探究

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.

常用示例
  1. 添加監聽器(最常用處理):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類,使之既可以寫異步執行結果,又具備監聽通道的功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章