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

Java 并發(fā)編程面試題Future 模式及實現(xiàn)方法

 更新時間:2025年04月26日 09:36:26   作者:代碼星辰  
FutureTask是Future接口的一個實現(xiàn),常與Callable一起使用,CompletableFuture是Java8引入的,擴展了Future的功能,支持異步任務(wù)的編排和組合,提供了更強大的函數(shù)式編程能力,這篇文章主要介紹了Java 并發(fā)編程面試題Future 模式及實現(xiàn)方法,需要的朋友可以參考下

1.什么是 Future 模式?Java 中是如何實現(xiàn)的?

(1)Future 模式是一種并發(fā)編程模式,它允許異步執(zhí)行代碼并在未來獲取其結(jié)果。在 Future 模式中,調(diào)用線程可以提交一個任務(wù)給另一個線程或線程池,并立即返回一個 Future 對象作為任務(wù)的代理。Future 對象表示了尚未完成的任務(wù),并允許調(diào)用線程在未來的某個時刻獲取任務(wù)的結(jié)果。Future 模式通常用于處理長時間運行的任務(wù),例如網(wǎng)絡(luò)請求或耗時的計算。通過使用 Future 模式,調(diào)用線程可以避免阻塞并繼續(xù)執(zhí)行其他任務(wù),同時仍然能夠獲得任務(wù)的結(jié)果。

(2)在 Java 中,F(xiàn)uture 模式是通過 Future 接口來實現(xiàn)的。Java 還提供了 CompletableFuture 類,它是 Future 接口的實現(xiàn),并提供了更豐富的功能,例如異步回調(diào)異常處理。Java 設(shè)計到的相關(guān)接口和類如下圖所示:

2.Callable、Future 與 FutureTask 分別是什么?

通常來說,我們使用 Runnable 和 Thread 來創(chuàng)建一個新的線程。但是它們有一個弊端,就是 run() 是沒有返回值的。而有時候我們希望開啟一個線程去執(zhí)行一個任務(wù),并且這個任務(wù)執(zhí)行完成后有一個返回值。JDK 提供了 Callable 接口與 Future 類為我們解決這個問題,這也是所謂的“異步”模型。

2.1.Callable 接口

(1)Callable 與 Runnable 類似,同樣是只有?個抽象方法的函數(shù)式接看。不同的是, Callable 提供的方法是有返回值的,而且支持泛型。Callable 接口的特點如下:

  • 為了實現(xiàn) Runnable,需要實現(xiàn)不返回任何內(nèi)容的 run() 方法,而對于Callable,需要實現(xiàn)在完成時返回結(jié)果的 call() 方法;
  • call() 方法可以引發(fā)異常,而 run() 則不能;
  • 為實現(xiàn) Callable 而必須重寫 call() 方法;
  • 不能直接替換 runnable,因為 Thread 類的構(gòu)造方法根本沒有 Callable;
@FunctionalInterface
public interface Callable<V> {
	V call() throws Exception; 
}
class MyThread1 implements Runnable {
    @Override
    public void run() {
        //無返回值
    }
}
class MyThread2 implements Callable {
    @Override
    public Object call() throws Exception {
        return 1;
    }
}

(2)那?般是怎么使用 Callable 的呢? Callable?般配合線程池工具 ExecutorService 來使用。這里只介紹 ExecutorService 可以使用 submit 方法來讓?個 Callable 接口執(zhí)行。它會返回?個 Future ,我們后續(xù)的程序可以通過這個 Future 的 get 方法得到結(jié)果。這里可以看?個簡單的使用案例:

class Task implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        // 模擬計算需要 3 秒
        Thread.sleep(3000);
        return 2;
    }
    public static void main(String args[]) throws ExecutionException, InterruptedException {
        // 使?
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        // ExecutorService.submit() 方法返回的其實就是 Future 的實現(xiàn)類 FutureTask
        Future<Integer> result = executor.submit(task);
        //注意調(diào)? get ?法會阻塞當(dāng)前線程,直到得到結(jié)果,所以實際編碼中建議使?可以設(shè)置超時時間的重載 get ?法
        System.out.println(result.get());
    }
}

輸出結(jié)果:

2

此外,Callable 可以配合 FutureTask 使用:

class Task implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        // 模擬計算需要 3 秒
        Thread.sleep(3000);
        return 2;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> task = new FutureTask<>(new Task());
        new Thread(task).start();
        Integer res = task.get();
        //注意調(diào)? get ?法會阻塞當(dāng)前線程,直到得到結(jié)果,所以實際編碼中建議使?可以設(shè)置超時時間的重載 get ?法
        System.out.println(res);
    }
}

2.2.Future 接口

(1)在 Java 中,F(xiàn)uture 類是一個泛型接口,位于 java.util.concurrent 包下,其包含的方法如下:

package java.util.concurrent;
// V 表示任務(wù)返回值的類型
public interface Future<V> {
    //成功取消任務(wù)返回 true,否則返回 false
    boolean cancel(boolean mayInterruptIfRunning);
    //判斷任務(wù)是否被取消
    boolean isCancelled();
    //判斷任務(wù)是否已經(jīng)執(zhí)行完成
    boolean isDone();
    //獲取任務(wù)執(zhí)行結(jié)果
    V get() throws InterruptedException, ExecutionException;
    //指定時間內(nèi)沒有返回計算結(jié)果就拋出 TimeOutException 異常
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

簡單理解 Future:現(xiàn)在有一個任務(wù),提交給了 Future 來處理。任務(wù)執(zhí)行期間我自己可以去做任何想做的事情。并且,在這期間我還可以取消任務(wù)以及獲取任務(wù)的執(zhí)行狀態(tài)。一段時間之后,我就可以 Future 那里直接取出任務(wù)執(zhí)行結(jié)果。

(2)cancel 方法是試圖取消?個線程的執(zhí)行。 注意是試圖取消,并不?定能取消成功。因為任務(wù)可能已完成、已取消、或者?些其它因素不能取消,存在取消失敗的可能。boolean 類型的返回值是“是否取消成功”的意思。參數(shù) paramBoolean 表示是否采用中斷的方式取消線程執(zhí)行。 所以有時候為了讓任務(wù)有能夠取消的功能,就使用 Callable 來代替 Runnable 。 如果為了可取消性而使用 Future 但又不提供可用的結(jié)果,則可以聲明 Future<?> 形式類型、并返回 null 作為底層任務(wù)的結(jié)果。

2.3.FutureTask 類

(1)上面介紹了 Future 接口。這個接口有?個實現(xiàn)類叫 FutureTask 。 FutureTask 是實現(xiàn)的 RunnableFuture 接口的,而 RunnableFuture 接口同時繼承了 Runnable 接口和 Future 接口

public interface RunnableFuture<V> extends Runnable, Future<V> {
	/**
	* Sets this Future to the result of its computation
	* unless it has been cancelled.
	*/
	void run(); 
}

(2)那 FutureTask 類有什么用?前面說到了 Future 只是?個接口,而它里面的 cancel、get、isDone 等方法要自己實現(xiàn)起來都是非常復(fù)雜的。所以 JDK 提供了?個 FutureTask 類來供我們使用。FutureTask 有兩個構(gòu)造函數(shù),可傳入 Callable 或者 Runnable 對象。實際上,傳入 Runnable 對象也會在方法內(nèi)部轉(zhuǎn)換為 Callable 對象

public class FutureTask<V> implements RunnableFuture<V> {
	//...
	public FutureTask(Callable<V> callable) {
	    if (callable == null)
	        throw new NullPointerException();
	    this.callable = callable;
	    this.state = NEW;
	}
	public FutureTask(Runnable runnable, V result) {
	    // 通過適配器 RunnableAdapter 來將 Runnable 對象 runnable 轉(zhuǎn)換成 Callable 對象
	    this.callable = Executors.callable(runnable, result);
	    this.state = NEW;
	}
}

FutureTask 相當(dāng)于對 Callable 進行了封裝,管理著任務(wù)執(zhí)行的情況,存儲了 Callable 的 call 方法的任務(wù)執(zhí)行結(jié)果。

(3)示例代碼如下:

class Task implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        //模擬計算需要?秒
        Thread.sleep(1000);
        return 2;
    }
    public static void main(String args[]) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newCachedThreadPool();
        FutureTask<Integer> futureTask = new FutureTask<>(new Task());
        executor.submit(futureTask);
        System.out.println(futureTask.get());
    }
}

使用上與第?個 Demo 有?點小的區(qū)別:

  • 此處調(diào)用 submit 方法是沒有返回值的,因為這里實際上是調(diào)用的 submit(Runnable task) 方法,而上面的 Demo,調(diào)用的是 submit(Callable<T> task) 方法。
  • 這里是使用 FutureTask 的 get 方法來獲取返回值,而上面的 Demo 是通過 submit 方法返回的 Future 去取值。 在很多高并發(fā)的環(huán)境下,有可能 Callable 和 FutureTask 會創(chuàng)建多次。FutureTask 能夠在高并發(fā)環(huán)境下確保任務(wù)只執(zhí)行?次。

(4)核心原理

  • 在主線程中需要執(zhí)行比較耗時的操作時,但又不想阻塞主線程時,可以把這些作業(yè)交給 Future 對象在后臺完成;
  • 當(dāng)主線程將來需要時,就可以通過 Future 對象獲得后臺作業(yè)的計算結(jié)果或者執(zhí)行狀態(tài);
  • 一般 FutureTask 多用于耗時的計算,主線程可以在完成自己的任務(wù)后,再去獲取結(jié)果;
  • 僅在計算完成時才能檢索結(jié)果;如果計算尚未完成,則阻塞 get() 方法,一旦計算完成,就不能再重新開始或取消計算;
  • get() 方法而獲取結(jié)果只有在計算完成時獲取,否則會一直阻塞直到任務(wù)轉(zhuǎn)入完成狀態(tài),然后會返回結(jié)果或者拋出異常;
  • get() 只計算一次,因此 get() 方法放到最后。
//比較 Runnable 和 Callable 這兩個接口
class MyThread1 implements Runnable {
    @Override
    public void run() {
        //無返回值
    }
}
class MyThread2 implements Callable {
    @Override
    public Object call() throws Exception {
        return 1;
    }
}
public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //使用 Runnable 創(chuàng)建線程
        new Thread(new MyThread1(), "AA").start();
        /*
        	使用 Callable 創(chuàng)建線程
            不能像上面那樣直接創(chuàng)建 new Thread(new MyThread2(), "BB").start();
        */
        //FutureTask
        FutureTask<Integer> futureTask1 = new FutureTask<>(new MyThread2());
        //使用 lambda 表達式進行簡化
        FutureTask<Integer> futureTask2 = new FutureTask<>(()->{
            System.out.println(Thread.currentThread().getName() + " enters the callable .");
            return 1;
        });
        //創(chuàng)建一個線程
        new Thread(futureTask2, "Luck").start();
        while (!futureTask2.isDone()) {
            System.out.println("wait...");
        }
        //調(diào)用 FutureTask 的get()
        System.out.println(futureTask2.get());
        //只進行一次計算
        System.out.println(futureTask2.get());
        System.out.println(Thread.currentThread().getName() + " is over !");
    }
}

(5)FutureTask 的幾種狀態(tài)

/**
 * state 可能的狀態(tài)轉(zhuǎn)變路徑如下:
 * NEW -> COMPLETING -> NORMAL
 * NEW -> COMPLETING -> EXCEPTIONAL
 * NEW -> CANCELLED
 * NEW -> INTERRUPTING -> INTERRUPTED
 */
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;

state 表示任務(wù)的運行狀態(tài),初始狀態(tài)為 NEW。運行狀態(tài)只會在 set、setException、cancel 方法中終止。COMPLETING、INTERRUPTING 是任務(wù)完成后的瞬時狀態(tài)。

3.CompletableFuture 類有什么用?

(1)Future 在實際使用過程中存在一些局限性,例如不支持異步任務(wù)的編排組合、獲取計算結(jié)果的 get() 方法為阻塞調(diào)用等。Java 8 才被引入 CompletableFuture 類可以解決 Future 的這些缺陷。CompletableFuture 除了提供了更為好用和強大的 Future 特性之外,還提供了函數(shù)式編程、異步任務(wù)編排組合(可以將多個異步任務(wù)串聯(lián)起來,組成一個完整的鏈?zhǔn)秸{(diào)用)等能力。

public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
	//...
}

(2)可以看到,CompletableFuture 同時實現(xiàn)了 Future 接口CompletionStage 接口。其中,CompletionStage 接口描述了一個異步計算的階段。很多計算可以分成多個階段或步驟,此時可以通過它將所有步驟組合起來,形成異步計算的流水線。CompletionStage 接口中的方法比較多,CompletableFuture 的函數(shù)式能力就是這個接口賦予的。從這個接口的方法參數(shù)可以發(fā)現(xiàn)其大量使用了 Java 8 引入的函數(shù)式編程

到此這篇關(guān)于Java 并發(fā)編程面試題 Future 模式的文章就介紹到這了,更多相關(guān)Java Future 模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis入門教程(四)之mybatis動態(tài)sql

    Mybatis入門教程(四)之mybatis動態(tài)sql

    這篇文章主要介紹了Mybatis入門教程(四)之mybatis動態(tài)sql的相關(guān)資料,涉及到動態(tài)sql及動態(tài)sql的作用知識,本文介紹的非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • Java抽象類和接口使用梳理

    Java抽象類和接口使用梳理

    對于面向?qū)ο缶幊虂碚f,抽象是它的一大特征之一,在?Java?中可以通過兩種形式來體現(xiàn)OOP的抽象:接口和抽象類,下面這篇文章主要給大家介紹了關(guān)于Java入門基礎(chǔ)之抽象類與接口的相關(guān)資料,需要的朋友可以參考下
    2022-02-02
  • 工廠方法在Spring框架中的運用

    工廠方法在Spring框架中的運用

    這篇文章介紹了工廠方法在Spring框架中的運用,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-10-10
  • SpringBoot使用maven指定依賴包的版本(解決示例)

    SpringBoot使用maven指定依賴包的版本(解決示例)

    我們在使用A依賴的時候,這個依賴有引入了第三方B依賴,這時候我想指定B依賴的版本號,下面?zhèn)€大家分享解決示例,對SpringBoot maven依賴包相關(guān)配置方法感興趣的朋友一起看看吧
    2024-04-04
  • Java消息隊列RabbitMQ入門詳解

    Java消息隊列RabbitMQ入門詳解

    這篇文章主要介紹了Java消息隊列RabbitMQ入門詳解,RabbitMQ是使用Erlang語言開發(fā)的開源消息隊列系統(tǒng),基于AMQP協(xié)議 來實現(xiàn),AMQP的主要特征是面向消息、隊列、路由(包括點對點和發(fā)布 /訂閱)、可靠性、安全,需要的朋友可以參考下
    2023-07-07
  • 深入理解ContextClassLoader加載器

    深入理解ContextClassLoader加載器

    這篇文章主要介紹了深入理解ContextClassLoader加載器,Thread?context?class?loader存在的目的主要是為了解決parent?delegation機制下無法干凈的解決的問題,需要的朋友可以參考下
    2023-10-10
  • JAVA中Comparable接口和自定義比較器示例講解

    JAVA中Comparable接口和自定義比較器示例講解

    這篇文章主要給大家介紹了關(guān)于JAVA中Comparable接口和自定義比較器的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • SpringBoot配置文件properties和yml的實現(xiàn)

    SpringBoot配置文件properties和yml的實現(xiàn)

    本文主要介紹了SpringBoot配置文件properties和yml的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • SpringBoot使用slf4j日志并輸出到文件中的操作方法

    SpringBoot使用slf4j日志并輸出到文件中的操作方法

    這篇文章主要介紹了SpringBoot使用slf4j日志并輸出到文件中,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • Java微信公眾平臺開發(fā)(8) 多媒體消息回復(fù)

    Java微信公眾平臺開發(fā)(8) 多媒體消息回復(fù)

    這篇文章主要為大家詳細介紹了Java微信公眾平臺開發(fā)第八步,微信多媒體消息回復(fù),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04

最新評論