欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的Future獲取任務(wù)返回值詳解

 更新時(shí)間:2023年12月22日 09:24:15   作者:Java面試365  
這篇文章主要介紹了Java中的Future獲取任務(wù)返回值詳解,在向線程池ThreadPoolExecutor提交任務(wù)時(shí),一般為了方便操作采用execute提交任務(wù),這時(shí)線程其實(shí)是無(wú)返回值的,需要的朋友可以參考下

Future獲取任務(wù)返回值

submit方法簽名

在向線程池ThreadPoolExecutor提交任務(wù)時(shí),一般為了方便操作采用execute提交任務(wù),這時(shí)線程其實(shí)是無(wú)返回值的,但是在生產(chǎn)中為了應(yīng)對(duì)各種各樣的需求,獲取線程返回值是必不可少的,所以SDK提供另一種任務(wù)提交方式submit,方法簽名如下

// 提交Runnable任務(wù)
Future<?> submit(Runnable task);
// 提交Callable任務(wù)
<T> Future<T> submit(Callable<T> task);
// 提交Runnable任務(wù)及結(jié)果引用  
<T> Future<T> submit(Runnable task, T result);

很明顯三個(gè)submit提交任務(wù)的返回值都是Future,其實(shí)Future是一個(gè)接口,F(xiàn)uture內(nèi)部提供五大方法

// 任務(wù)取消操作 參數(shù)是允許中斷正在運(yùn)行的線程
boolean cancel(boolean mayInterruptIfRunning);
// 判斷任務(wù)是否取消
boolean isCancelled();
// 判斷任務(wù)是否結(jié)束
boolean isDone();
// 阻塞式的獲取任務(wù)返回結(jié)果
V get() throws InterruptedException, ExecutionException;
// 支持超時(shí)功能
V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

需要注意的是,兩個(gè)get都是阻塞式獲取線程返回結(jié)果的,所以當(dāng)調(diào)用get后,調(diào)用線程就會(huì)睡眠,只有當(dāng)任務(wù)返回結(jié)果后才會(huì)喚醒線程往下執(zhí)行。

submit方法說(shuō)明

submit的三大提交方法是有所不同的,不同的場(chǎng)景對(duì)應(yīng)不同的方法。

  • submit(Runnable task)方法參數(shù)是Runnable接口,實(shí)現(xiàn)Runnable的線程是沒有返回值的,所以這個(gè)submit雖然能夠返回Future對(duì)象,調(diào)用其get方法還是返回null值的,F(xiàn)uture只能當(dāng)斷言使用,類似于Thread.join方法。
  • submit(Callable task)方法參數(shù)是Callable接口(線程如果實(shí)現(xiàn)Callable接口,那么要求實(shí)現(xiàn)call()方法,這個(gè)方法支持返回值),顯然實(shí)現(xiàn)Callable的線程是能夠返回值的,所以這個(gè)submit能夠返回Future對(duì)象,同時(shí)調(diào)用get方法還能得到返回值。
  • Future submit(Runnable task, T result);這個(gè)方法的簽名稍微有點(diǎn)復(fù)雜,和第一種提交方式相比多了result對(duì)象,這個(gè)對(duì)象其實(shí)就是后面Future.get出來(lái)的返回值,result可以認(rèn)為是主線程和子線程的橋梁,通過(guò)result實(shí)現(xiàn)主線程和子線程的通信,可能這樣說(shuō)還是有些模糊,可以參考如下示例思考。
public class Test4 {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        Apple apple = new Apple("red apple",5999.9);
        System.out.println("調(diào)用前==" +apple);
        Task task = new Task(apple);
        Future<Apple> submit = executor.submit(task, apple);
        // 阻塞式獲取
        Apple result = submit.get();
        System.out.println("調(diào)用前==" + result);
    }
}
// 實(shí)現(xiàn)線程方法
class Task implements Runnable{
    // 非常重要的一般 相當(dāng)于是參數(shù)傳遞的形式,可以到線程中修改
    Apple apple;
    public Task(Apple apple){
        this.apple = apple;
    }
    @Override
    public void run() {
        // 在線程中可以操作傳入的對(duì)象
        apple.setName("green apple");
        System.out.println("操作Apple");
    }
}
class Apple{
    private String name;
    private double price;
    public Apple(String name,double price){
        this.name = name;
        this.price = price;
    }
	// 省略get set方法 以及toString方法
}

返回結(jié)果如下

Future的實(shí)現(xiàn)-FutureTask

Future只是一個(gè)接口,有接口了必須介紹下它的具體實(shí)現(xiàn)FutureTask,F(xiàn)utureTask是一個(gè)工具類,這個(gè)工具類有兩個(gè)構(gòu)造函數(shù),簽名如下

public FutureTask(Callable<V> callable)
public FutureTask(Runnable runnable, V result)

FutureTask實(shí)現(xiàn)了Runnable,和Future接口,由于現(xiàn)實(shí)了Runnable接口,所以FutureTask可以作為參數(shù)提交給線程池ThreadPoolExecutor,也可以作為構(gòu)造參數(shù)傳遞給Thread,而FutureTask還實(shí)現(xiàn)了Future就可以獲取線程的返回值,所以我們可以得到FutureTask的兩種用法。

方法一:作為參數(shù)提交到線程池中執(zhí)行。

// 定義對(duì)象
FutureTask<Integer> task = new FutureTask(()->{
    return 1+2;
});
// 定義線程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 不要使用這里的返回值,就算是FutureTask實(shí)現(xiàn)了Future對(duì)象,
// 但是Future也現(xiàn)實(shí)了Runnable接口返回值為空
Future<?> submit = executorService.submit(task);
// 返回值獲取
System.out.println(task.get());
executorService.shutdown();

方法二:作為構(gòu)造參數(shù)傳遞給Thread

// 定義對(duì)象
FutureTask<Integer> task = new FutureTask(()->{
    return 1+2;
});
// 線程構(gòu)造方法,傳入Runnable的子類
Thread thread = new Thread(task);
thread.start();
System.out.println(task.get());

FutureTask的實(shí)戰(zhàn)

在數(shù)學(xué)家華羅庚的文章中提出燒水泡茶的最優(yōu)解,如下所示

用到編程世界中,那么將上述最優(yōu)解可以拆分為兩個(gè)線程去執(zhí)行

線程A需要完成洗水壺,燒水的工作,完成后等待線程B將洗茶壺,洗茶杯,拿茶葉三個(gè)步驟做完,所以線程A在內(nèi)部需要等待線程B執(zhí)行完畢才能完成最后泡茶的工作,這里可以采用Thread.join,CountDownLatch,F(xiàn)uture都可以實(shí)現(xiàn),以Future為例。

public class UseFutureTask {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 定義線程B的執(zhí)行
        FutureTask<String> futureTaskB = new FutureTask<>(new ThreadB());
        // 定義線程A的執(zhí)行
        FutureTask futureTaskA = new FutureTask(new ThreadA(futureTaskB),null);
        // 線程執(zhí)行
        Thread threadA = new Thread(futureTaskA);
        Thread threadB = new Thread(futureTaskB);
        threadA.start();
        threadB.start();
        futureTaskA.get();
    }
}
// 用于線程A 完成洗水壺 燒水
class ThreadA implements Runnable {
    FutureTask<String> futureTask;
    public ThreadA(FutureTask<String> futureTask){
        this.futureTask = futureTask;
    }
    @Override
    public void run() {
        try {
            System.out.println("ThreadA 洗水壺");
            TimeUnit.SECONDS.sleep(1);
            System.out.println("ThreadA 燒水");
            TimeUnit.SECONDS.sleep(15);
            // 需要獲取線程B的茶葉
            String teaName = futureTask.get();
            System.out.println("ThreadA 泡茶===="+teaName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
// 用于線程B 完成洗茶壺 洗茶杯 拿茶葉 需要返回茶葉的
class ThreadB implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("ThreadB 洗茶壺");
        TimeUnit.SECONDS.sleep(1);
        System.out.println("ThreadB 洗茶杯");
        TimeUnit.SECONDS.sleep(2);
        System.out.println("ThreadB 拿茶葉");
        TimeUnit.SECONDS.sleep(1);
        return "鐵觀音";
    }
}

執(zhí)行結(jié)果

到此這篇關(guān)于Java中的Future獲取任務(wù)返回值詳解的文章就介紹到這了,更多相關(guān)Future獲取任務(wù)返回值內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論