Java 任务队列:ExecutorService 和 ThreadPoolExecutor
在 Java 多线程应用程序中,任务及其执行的管理是关键任务之一。与其为每个任务创建新线程(这既昂贵又低效),开发者使用任务队列(Task Queues)结合线程池。这可以控制同时运行的线程数量、重用线程,并平稳处理峰值负载。
Java 中处理任务队列的基础是 java.util.concurrent 框架,该框架在 Java 5 中引入。主要组件包括:ExecutorService、ThreadPoolExecutor 以及各种 BlockingQueue 实现。
1. ExecutorService — 高级接口
ExecutorService 是一个接口,提供异步执行任务的方法。它隐藏了线程管理的细节。获取其实例的最流行方式是使用 Executors 类的工厂方法:
ExecutorService executor = Executors.newFixedThreadPool(4); // 4 个线程的线程池executor.submit(() -> { System.out.println("任务在线程中执行:" + Thread.currentThread().getName());});executor.shutdown(); // 在所有任务完成后关闭然而,工厂方法的配置能力有限。为了进行精细调整,可以直接使用 ThreadPoolExecutor。
2. ThreadPoolExecutor — 可配置的线程池
ThreadPoolExecutor 是该框架的核心。它接受任务队列、饱和策略、线程存活时间等参数。完整构造函数如下:
public ThreadPoolExecutor( int corePoolSize, // 最小线程数 int maximumPoolSize, // 最大线程数 long keepAliveTime, // 线程空闲后存活时间 TimeUnit unit, // 时间单位 BlockingQueue<Runnable> workQueue, // 任务队列 RejectedExecutionHandler handler // 溢出时的策略);使用自定义队列创建线程池的示例:
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 4, 30, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.AbortPolicy() // 默认策略 — 抛出异常);executor.execute(() -> { // 繁重任务});executor.shutdown();3. BlockingQueue — 任务队列的基础
队列类型决定了任务如何存储并传递给线程。最流行的实现包括:
LinkedBlockingQueue— 基于链表的无界队列。如果不设置容量,可能导致内存溢出。ArrayBlockingQueue— 基于数组的有界队列。允许控制等待任务的数量。SynchronousQueue— 零容量队列。每个任务直接传递给线程,无队列等待。PriorityBlockingQueue— 优先级队列。任务按优先级排序(实现Comparable)。
使用有界队列和拒绝策略的示例:
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10);ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 5, 10, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.CallerRunsPolicy() // 任务在调用线程中执行);for (int i = 0; i < 20; i++) { executor.submit(() -> { Thread.sleep(100); return Math.random(); });}executor.shutdown();4. 饱和策略(RejectedExecutionHandler)
当队列溢出时