使用 Lambdas 定義內聯非同步任務

雖然良好的軟體設計通常可以最大限度地提高程式碼的可重用性,但有時通過 Lambda 表示式在程式碼中內聯定義非同步任務以最大化程式碼可讀性會很有用。

在這個例子中,我們將建立一個包含 main() 方法的類。在此方法中,我們將使用 Lambda 表示式來建立和執行 Callable 和 Runnable <T>的例項。

AsyncExample3.java

import lombok.extern.java.Log;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

@Log
public class AsyncExample3 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        List<Future<Integer>> futures = new ArrayList<>();
        for(int i = 0; i < 5; i++){
            final int index = i;
            executorService.execute(() -> {
                int timeout = getTimeout();
                log.info(String.format("Runnable %d has been submitted and will sleep for %d seconds", index, timeout));
                try {
                    TimeUnit.SECONDS.sleep(timeout);
                } catch (InterruptedException e) {
                    log.warning(e.getMessage());
                }
                log.info(String.format("Runnable %d has finished sleeping", index));
            });
            Future<Integer> submittedFuture = executorService.submit(() -> {
                int timeout = getTimeout();
                log.info(String.format("Callable %d will begin sleeping", index));
                try {
                    TimeUnit.SECONDS.sleep(timeout);
                } catch (InterruptedException e) {
                    log.warning(e.getMessage());
                }
                log.info(String.format("Callable %d is done sleeping", index));
                return timeout;
            });
            futures.add(submittedFuture);
        }
        executorService.shutdown();
        while(!futures.isEmpty()){
            for(int j = 0; j < futures.size(); j++){
                Future<Integer> f = futures.get(j);
                if(f.isDone()){
                    try {
                        int timeout = f.get();
                        log.info(String.format("A task just completed after sleeping for %d seconds", timeout));
                        futures.remove(f);
                    } catch (InterruptedException | ExecutionException e) {
                        log.warning(e.getMessage());
                    }
                }
            }
        }
    }

    public static int getTimeout(){
        return ThreadLocalRandom.current().nextInt(1, 20);
    }
}

注意事項:

在上面的輸出中有幾點需要注意,

  1. Lambda 表示式可以訪問定義它們的作用域可用的變數和方法,但所有變數必須是最終的(或有效的最終)才能在 lambda 表示式中使用。
  2. 我們不必明確指定我們的 Lambda 表示式是 Callable 還是 Runnable <T>,返回型別由返回型別自動推斷。