MST

星途 面试题库

面试题:Java中Executor接口与ExecutorService接口的区别及使用选择

阐述Java中Executor接口和ExecutorService接口的主要区别。在一个需要提交任务并获取任务执行结果,同时还需要管理线程池生命周期的场景中,为什么要选择ExecutorService而不是直接使用Executor接口,结合代码示例说明如何正确使用ExecutorService接口来满足该场景需求。
23.8万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. Executor接口和ExecutorService接口的主要区别

  • Executor接口
    • 是一个非常基础的接口,它只定义了一个方法 execute(Runnable task),用于提交一个 Runnable 任务到线程池中执行。它不提供任务执行结果的获取,也没有对线程池生命周期管理的方法。主要目的是将任务的提交和执行分离,简化任务执行的管理。
  • ExecutorService接口
    • 继承自 Executor 接口,扩展了许多功能。它不仅可以提交 Runnable 任务,还可以提交 Callable 任务(Callable 任务有返回值,而 Runnable 任务无返回值)。
    • 提供了获取任务执行结果的方法,例如通过 Future 对象来获取 Callable 任务的执行结果。
    • 具备管理线程池生命周期的方法,如 shutdown() 用于平滑关闭线程池,shutdownNow() 用于立即关闭线程池等。

2. 选择ExecutorService的原因

在需要提交任务并获取任务执行结果,同时管理线程池生命周期的场景中,Executor 接口无法满足获取任务执行结果和管理线程池生命周期的需求。而 ExecutorService 接口集成了这些功能,所以更适合该场景。

3. 代码示例

import java.util.concurrent.*;

public class ExecutorServiceExample {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 提交Callable任务
        Future<Integer> future = executorService.submit(() -> {
            // 模拟任务执行
            Thread.sleep(2000);
            return 42;
        });

        try {
            // 获取任务执行结果,这里会阻塞直到任务完成
            Integer result = future.get();
            System.out.println("任务执行结果: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
            executorService.shutdown();
        }
    }
}

在上述代码中:

  • 通过 Executors.newFixedThreadPool(2) 创建了一个固定大小为2的线程池。
  • 使用 executorService.submit(Callable<T> task) 提交了一个 Callable 任务,该任务返回一个 Future 对象。
  • 通过 future.get() 获取任务的执行结果,此操作会阻塞当前线程直到任务完成。
  • 最后通过 executorService.shutdown() 平滑关闭线程池。