Java ExecutorService 类

ExecutorService 是 Java 并发编程中的一个核心接口,它属于 java.util.concurrent 包。

ExecutorService 提供了一种更高级的线程管理方式,允许开发者高效地执行异步任务,而无需手动创建和管理线程。

ExecutorService 的主要作用包括:

  • 线程池管理:自动管理线程的生命周期,减少线程创建和销毁的开销。
  • 任务调度:支持提交 RunnableCallable 任务,并返回 Future 对象以跟踪任务执行状态。
  • 资源优化:通过线程池复用线程,提高系统性能。

ExecutorService 的核心方法

ExecutorService 提供了多种方法来提交、管理和控制任务的执行。以下是几个关键方法:

submit()

用于提交一个任务(RunnableCallable)并返回 Future 对象,以便检查任务是否完成或获取返回值。

实例

ExecutorService executor = Executors.newFixedThreadPool(2);
Future<?> future = executor.submit(() -> {
    System.out.println("Task is running");
});

execute()

仅用于提交 Runnable 任务,不返回任何结果。

实例

executor.execute(() -> {
    System.out.println("Task executed");
});

shutdown()

优雅关闭线程池,不再接受新任务,但会等待已提交的任务完成。

实例

executor.shutdown();

shutdownNow()

立即关闭线程池,尝试中断所有正在执行的任务,并返回未执行的任务列表。

实例

List<Runnable> notExecutedTasks = executor.shutdownNow();

awaitTermination()

等待线程池关闭,直到所有任务完成或超时。

实例

executor.awaitTermination(10, TimeUnit.SECONDS);

如何创建 ExecutorService

Java 提供了 Executors 工具类来创建不同类型的线程池:

newFixedThreadPool(int nThreads)

创建固定大小的线程池,适用于负载稳定的任务。

实例

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);

newCachedThreadPool()

创建可缓存的线程池,适用于短生命周期的异步任务。

实例

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

newSingleThreadExecutor()

创建单线程的线程池,适用于顺序执行的任务。

实例

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

newScheduledThreadPool(int corePoolSize)

创建支持定时或周期性任务的线程池。

实例

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);

使用示例

提交 Runnable 任务

实例

ExecutorService executor = Executors.newFixedThreadPool(2);

executor.submit(() -> {
    System.out.println("Task 1 running");
});

executor.submit(() -> {
    System.out.println("Task 2 running");
});

executor.shutdown();

提交 Callable 任务并获取结果

实例

ExecutorService executor = Executors.newFixedThreadPool(2);

Future<String> future = executor.submit(() -> {
    Thread.sleep(1000);
    return "Task completed";
});

try {
    String result = future.get(); // 阻塞直到任务完成
    System.out.println(result);
} catch (Exception e) {
    e.printStackTrace();
}

executor.shutdown();

最佳实践

  1. 合理设置线程池大小

    • CPU 密集型任务:线程数 = CPU 核心数 + 1
    • IO 密集型任务:线程数 = CPU 核心数 * 2
  2. 避免内存泄漏

    • 确保调用 shutdown()shutdownNow() 关闭线程池。
  3. 处理异常

    • 使用 try-catch 捕获任务中的异常,防止线程意外终止。
  4. 使用 Future 管理任务

    • 通过 Future.get() 获取任务结果或检查任务状态。