面试题:Java 创建线程池有哪些方式?

在 Java 中,创建线程池的方式主要有以下几种:


1. 使用 Executors 工厂类

Executors 是 Java 提供的一个工具类,提供了多种创建线程池的静态工厂方法。以下是常见的几种线程池:

(1)固定大小线程池(FixedThreadPool)
  • 特点:线程池中的线程数量固定。
  • 适用场景:适用于负载较重的服务器,需要限制线程数量以避免资源耗尽。
(2)单线程线程池(SingleThreadExecutor)
  • 特点:线程池中只有一个线程。
  • 适用场景:适用于需要保证任务顺序执行的场景。
(3)缓存线程池(CachedThreadPool)
  • 特点:线程池中的线程数量不固定,根据需要创建新线程,空闲线程会被回收。
  • 适用场景:适用于执行大量短期异步任务。
(4)定时任务线程池(ScheduledThreadPool)
  • 特点:支持定时及周期性任务执行。
  • 适用场景:适用于需要定时执行任务的场景。
(5)单线程定时任务线程池(SingleThreadScheduledExecutor)
  • 特点:只有一个线程的定时任务线程池。
  • 适用场景:适用于需要单线程定时执行任务的场景。

2. 使用 ThreadPoolExecutor 构造函数

ThreadPoolExecutor 是 Java 线程池的核心实现类,通过其构造函数可以更灵活地创建线程池。

构造函数参数
  • corePoolSize:核心线程数。
  • maximumPoolSize:最大线程数。
  • keepAliveTime:空闲线程的存活时间。
  • unit:存活时间的单位。
  • workQueue:任务队列。
  • threadFactory:线程工厂。
  • handler:拒绝策略。
示例
import java.util.concurrent.*;

public class ThreadPoolExecutorExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2, // 核心线程数
            5, // 最大线程数
            60, // 空闲线程存活时间
            TimeUnit.SECONDS, // 时间单位
            new LinkedBlockingQueue<>(10), // 任务队列
            Executors.defaultThreadFactory(), // 线程工厂
            new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
        );

        executor.execute(() -> System.out.println("任务执行"));
        executor.shutdown();
    }
}

3. 使用 ForkJoinPool

ForkJoinPool 是 Java 7 引入的线程池,适用于分治任务的并行执行。

特点
  • 支持工作窃取(Work-Stealing)算法,提高并行任务的执行效率。
  • 适用于递归任务或分治任务。
示例
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

public class ForkJoinPoolExample {
    public static void main(String[] args) {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        int result = forkJoinPool.invoke(new FibonacciTask(10));
        System.out.println("Fibonacci 结果: " + result);
    }
}

class FibonacciTask extends RecursiveTask<Integer> {
    private final int n;

    FibonacciTask(int n) {
        this.n = n;
    }

    @Override
    protected Integer compute() {
        if (n <= 1) {
            return n;
        }
        FibonacciTask task1 = new FibonacciTask(n - 1);
        task1.fork();
        FibonacciTask task2 = new FibonacciTask(n - 2);
        return task2.compute() + task1.join();
    }
}

4. 自定义线程池

通过继承 ThreadPoolExecutor 或实现 ExecutorService 接口,可以创建自定义的线程池。

示例
import java.util.concurrent.*;

public class CustomThreadPool extends ThreadPoolExecutor {
    public CustomThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        System.out.println("任务执行前: " + r);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        System.out.println("任务执行后: " + r);
    }

    public static void main(String[] args) {
        CustomThreadPool executor = new CustomThreadPool(2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        executor.execute(() -> System.out.println("任务执行"));
        executor.shutdown();
    }
}

5. 总结

创建方式特点适用场景
Executors.newFixedThreadPool固定线程数负载较重的服务器
Executors.newSingleThreadExecutor单线程需要顺序执行的任务
Executors.newCachedThreadPool线程数动态调整大量短期异步任务
Executors.newScheduledThreadPool支持定时任务定时任务
ThreadPoolExecutor灵活配置线程池参数需要精细控制的场景
ForkJoinPool支持分治任务和工作窃取递归任务或分治任务
自定义线程池完全自定义线程池行为特殊需求的场景

根据具体需求选择合适的线程池创建方式,可以提高程序的性能和可维护性。

THE END
点赞10 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容