Java中的线程池概述

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池管理着多个线程,将任务分配给空闲线程执行,执行完任务的线程不会销毁,而是继续等待新的任务,从而实现线程的复用。

线程池的作用

  • 降低资源消耗:通过复用已创建的线程,减少了线程创建和销毁所带来的开销,降低了系统资源的消耗。
  • 提高响应速度:当有新任务提交时,由于线程已经存在,无需等待线程创建,可立即执行任务,提高了响应速度。
  • 方便线程管理:线程池可以对线程进行统一的分配、调优和监控,例如可以设置线程的最大数量、控制线程的执行顺序等。

创建和使用线程池

1. 使用 Executors 工厂类创建线程池

Executors 是 Java 提供的一个线程池工厂类,它提供了一些静态方法来创建不同类型的线程池。以下是一个简单的示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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

        // 提交任务到线程池
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            executorService.submit(() -> {
                System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskId + " is completed.");
            });
        }

        // 关闭线程池
        executorService.shutdown();
    }
}

上述代码中,首先使用 Executors.newFixedThreadPool(3) 创建了一个固定大小为 3 的线程池,然后通过 executorService.submit() 方法向线程池提交了 5 个任务,最后调用 executorService.shutdown() 方法关闭线程池。

2. 使用 ThreadPoolExecutor 类手动创建线程池

ThreadPoolExecutor 是线程池的核心实现类,可以通过构造函数手动配置线程池的各种参数。

import java.util.concurrent.*;

public class ManualThreadPoolExample {
    public static void main(String[] args) {
        // 手动创建线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                5, // 最大线程数
                60, // 线程空闲时间
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10) // 任务队列
        );

        // 提交任务到线程池
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskId + " is completed.");
            });
        }

        // 关闭线程池
        executor.shutdown();
    }
}

常见的线程池类型

1. 固定大小线程池(FixedThreadPool

使用 Executors.newFixedThreadPool(int nThreads) 方法创建,线程池中的线程数量固定,当有新任务提交时,如果有空闲线程则立即执行,否则将任务放入任务队列等待。

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

2. 单线程线程池(SingleThreadExecutor

使用 Executors.newSingleThreadExecutor() 方法创建,线程池只有一个线程,所有任务按照提交顺序依次执行。

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

3. 缓存线程池(CachedThreadPool

使用 Executors.newCachedThreadPool() 方法创建,线程池中的线程数量可以动态调整,当有新任务提交时,如果有空闲线程则立即执行,否则创建新线程执行任务。如果线程空闲时间超过 60 秒,则会被回收。

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

4. 定时线程池(ScheduledThreadPool

使用 Executors.newScheduledThreadPool(int corePoolSize) 方法创建,线程池可以执行定时任务和周期性任务。

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
// 延迟 2 秒后执行任务
scheduledThreadPool.schedule(() -> System.out.println("Task is executed."), 2, TimeUnit.SECONDS);

需要注意的是,从 Java 7 开始,《阿里巴巴 Java 开发手册》建议尽量不使用 Executors 工厂类来创建线程池,而是通过 ThreadPoolExecutor 手动创建,这样可以更好地控制线程池的参数,避免出现资源耗尽等问题。