使用 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>,返回类型由返回类型自动推断。