Java并發(fā)編程高級篇(三):執(zhí)行器中執(zhí)行任務并返回結果

執(zhí)行器框架的優(yōu)質(zhì)之一是可以并發(fā)地執(zhí)行任務,并將任務執(zhí)行結果返回。要想實現(xiàn)這個功能,需要JDK中的兩個接口。

  • Callable:這個接口帶有一個call()方法,你可以在這個方法里面實現(xiàn)任務執(zhí)行邏輯,同時這個接口帶有一個泛型參數(shù),你可以通過這個泛型參數(shù)來指定返回結果的類型。
  • Future:這個接口生命了一些方法來獲取由Callable對象產(chǎn)生的結果,并管理他們的狀態(tài)。

創(chuàng)建一個類FactorialCalculator實現(xiàn)Callable接口,用于計算階乘。泛型參數(shù)使用Integer來規(guī)定返回值為整型。

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * 創(chuàng)建一個名為FactorialCalculator類并實現(xiàn)Callable<Integer>接口
 *
 * 用來計算number的階乘
 *
 * Created by hadoop on 2016/11/2.
 */
public class FactorialCalculator implements Callable<Integer> {
    private Integer number;

    public FactorialCalculator(Integer number) {
        this.number = number;
    }

    @Override
    public Integer call() throws Exception {
        int result = 1;

        if (number > 2) {
            for (int i = 2; i <= number; i++) {
                result *= i;
            }
        }

        TimeUnit.MILLISECONDS.sleep(200);

        return result;
    }
}

然后實現(xiàn)Main方法,循環(huán)10次,每次產(chǎn)生一個隨機整數(shù),然后調(diào)用FactorialCalculator來求這個整數(shù)的階乘。注意這里使用submit()方法來提交callable任務,因為這個方法會返回一個Future對象,而不是前面兩節(jié)那樣使用的是execute方法來執(zhí)行Runnable。

使用Futuee對象不但可以用來獲取線程任務的返回值,還可以用于獲取線程執(zhí)行狀態(tài)。

  • isDone():用于檢查任務是否執(zhí)行完成。
  • get():用于獲取Callable的call()方法執(zhí)行的返回結果,get()方法將一直等待call()方法執(zhí)行完成。如果等待過程中線程中斷了,那么將拋出InterrupedException異常,如果call()方法執(zhí)行異常,那么get()方法將接著拋出ExecutionException。
  • get(long timeout, TimeUnit unit):等待一段時間,如果任務沒有執(zhí)行完畢,那么返回null。
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

/**
 * 在執(zhí)行器中執(zhí)行任務并返回結果
 *
 * 執(zhí)行器框架的優(yōu)勢之一在于可以并行執(zhí)行任務,并且返回結果。Java并發(fā)API通過以下兩個接口來s實現(xiàn)這個功能。
 * 1. Callable接口:這個借口生命了call()方法,你可以在這個方法中實現(xiàn)具體的處理邏輯。
 *    Callable接口帶有泛型參數(shù),這意味著call()方法可以返回該數(shù)據(jù)類型的對象。
 * 2. Future接口:這個接口用來接收Callable接口產(chǎn)生的結果,并管理他們的狀態(tài)。
 *
 * 在本節(jié)我們學習了使用Callable接口來啟動并發(fā)任務并返回結果。
 * 我么編寫了FactorialCalculator類,它實現(xiàn)了帶有泛型參數(shù)Integer的Callable接口。
 * 因此這個Integer類型將作為在調(diào)用call()方法的返回值類型。
 *
 * 另一個關鍵點在于Main類,在這個類中我們使用了submit()方法,發(fā)送一個Callable對象到執(zhí)行器中。
 * 這個submit()方法接收Callable對象作為參數(shù),然后返回Future對象。
 * Future對象可以用于以下兩個目的。
 * 1. 控制任務的狀態(tài):可以取消或者檢查任務是否完成。在這里我們使用了isDone方法來判斷任務是否完成。
 * 2. 通過get()方法,接收call()方法返回的結果。這個方法一直等到call()方法執(zhí)行完成并返回結果。
 *    如果get()方法在等待結果時線程中斷了,將拋出一個InterruptedException。
 *    如果call()方法拋出異常,那么get方法拋出ExecutionException。
 *
 * Future對象還聽了另一個future.get(1000, TimeUnit.NANOSECONDS)方法來接受返回值。
 * 如果等待(1000, TimeUnit.NANOSECONDS)時間,call()方法還沒有執(zhí)行結束,那么將直接返回null值。
 *
 * Created by hadoop on 2016/11/2.
 */
public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(2);

        List<Future<Integer>> futures = new ArrayList<Future<Integer>>();

        Random random = new Random();

        for (int i = 0; i < 10; i++) {
            Integer number = random.nextInt(10);

            FactorialCalculator calculator = new FactorialCalculator(number);

            Future<Integer> future = executor.submit(calculator);

            futures.add(future);
        }

        do {
            //System.out.printf("Main: Number of the completed Tasks: %d\n", executor.getCompletedTaskCount());

            for (int i = 0; i < futures.size(); i++) {
                Future<Integer> future = futures.get(i);
                //System.out.printf("Main: Tasks %d: %s\n", i, future.isDone());
            }

            try {
                TimeUnit.MILLISECONDS.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        } while (executor.getCompletedTaskCount() < futures.size());

        for (int i = 0; i < futures.size(); i++) {
            Future<Integer> future = futures.get(i);
            System.out.printf("Main: Tasks %d: %d\n", i, future.get());
            //System.out.printf("Main: Tasks %d: %d\n", i, future.get(1000, TimeUnit.NANOSECONDS));
        }

        executor.shutdown();
    }
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容