Java併發程式設計-Future系列之Future的介紹和基本用法

西召發表於2019-03-26

多執行緒(Multithreading)是Java的一個特性,它可以允許一個程式的多個部分(也就是執行緒)併發地執行,以達到最大程度利用CPU的目的。

關於多執行緒程式設計(Multithread Programming),下面介紹一下Future的特性和基本用法。

dogs_multithread_programming

About Future

Future(java.util.concurrent Interface Future<V>)表示非同步計算的結果。Future介面提供了檢查計算是否完成、檢查計算是否被取消、等待計算完成並獲取計算結果等方法。

A Future represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation. The result can only be retrieved using method get when the computation has completed, blocking if necessary until it is ready. Cancellation is performed by the cancel method. Additional methods are provided to determine if the task completed normally or was cancelled. Once a computation has completed, the computation cannot be cancelled. If you would like to use a Future for the sake of cancellability but not provide a usable result, you can declare types of the form Future<?> and return null as a result of the underlying task.

docs.oracle.com/javase/8/do…

Future Methods

下面對Future的幾個方法做一下簡要介紹並提供程式碼演示。

private static ExecutorService executor = Executors.newSingleThreadExecutor();

public static Future<Integer> calculate(Integer input) {
    return executor.submit(() -> {
        Thread.sleep(3000);
         return input * input;
    });

}
複製程式碼

get()

V get()

Waits if necessary for the computation to complete, and then retrieves its result.
複製程式碼

get()方法使用者返回計算結果,如果計算還沒有完成,則在get的時候會進行阻塞,直到獲取到結果為止。

get() Sample Example

Future<Integer> calculateFuture = calculate(100);

System.out.println("calculate result: "+calculateFuture.get());
複製程式碼

在阻塞3s以後,可以得到執行結果:

calculate result: 10000
複製程式碼

get(long timeout, TimeUnit unit)

V	get(long timeout, TimeUnit unit)

Waits if necessary for at most the given time for the computation to complete, and then retrieves its result, if available.
複製程式碼

get(long timeout, TimeUnit unit)方法的耐心是有限的,如果在指定時間內沒有完成計算,則會丟擲TimeoutException.

get(long timeout, TimeUnit unit) Sample Example

Future<Integer> calculateFuture = calculate(100);

System.out.println(calculateFuture.get(2, TimeUnit.SECONDS));
複製程式碼

等待2s以後,丟擲異常:

Exception in thread "main" java.util.concurrent.TimeoutException
複製程式碼

isDone()

boolean	isDone()

Returns true if this task completed.
複製程式碼

isDone()方法用於判斷當前Future是否執行完成。

isDone() Sample Example

Future<Integer> calculateFuture = calculate(100);

System.out.println(calculateFuture.isDone());
while (!calculateFuture.isDone()){ }
System.out.println(calculateFuture.isDone());
複製程式碼

首先輸出false,迴圈3秒以後輸出true

cancel(boolean mayInterruptIfRunning)

boolean	cancel(boolean mayInterruptIfRunning)

Attempts to cancel execution of this task.
複製程式碼

取消當前執行緒的執行。參數列示是否線上程執行的過程中阻斷。

isCancelled()

boolean	isCancelled()

Returns true if this task was cancelled before it completed normally.
複製程式碼

判斷當前task是否被取消。

isCancelled() Sample Example

Future<Integer> calculateFuture = calculate(100);

System.out.println("isCancelled = "+calculateFuture.isCancelled());
System.out.println("cancel success = "+calculateFuture.cancel(true));
System.out.println("isCancelled = "+calculateFuture.isCancelled());
複製程式碼

Future ExecutorService

Java_Concurrent_Future_ExecutorService

下面提供一個通過執行緒池來非同步獲取執行結果並彙總的程式碼示例。

Callable<Long> callable = new Callable<Long>() {
    @Override
    public Long call() throws Exception {

        long start = System.currentTimeMillis();
        Thread.sleep(100);
        long end = System.currentTimeMillis();

        long seed = end - start;
        System.out.println("seed=" + seed);

        return seed;
    }
};

List<Callable<Long>> tasks = new ArrayList<>();
tasks.add(callable);
tasks.add(callable);
tasks.add(callable);
tasks.add(callable);
tasks.add(callable);
tasks.add(callable);
tasks.add(callable);
tasks.add(callable);
tasks.add(callable);
tasks.add(callable);

int poolSize = Runtime.getRuntime().availableProcessors();
System.out.println("poolSize=" + poolSize);
ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
List<Future<Long>> futures = executorService.invokeAll(tasks);

long result = 0;
for (Future<Long> future : futures) {
    result += future.get();
}
System.out.println("result=" + result);
executorService.shutdown();
複製程式碼

執行程式的主機是8核的,因此啟動了8個執行緒,每次會同時執行8個task。

下面是執行結果:

poolSize=8
seed=109
seed=109
seed=109
seed=109
seed=109
seed=109
seed=109
seed=109
seed=110
seed=110
result=1092
複製程式碼

links

SourceCode-Github

Future-JSE8

Future-baeldung.com

Future-geeksforgeeks.org

Future-dzone.com/

相關文章