Java 并发编程学习(七):正确地创建线程池

线程池的正确创建方式

虽然Executors类中提供了许多的工厂方法来创建各种的线程池,但是在实际的生产环境中,却不推荐直接使用这些线程池。国内大厂阿里巴巴的Java开发指导手册就约束了这个行为。不推荐使用的原因主要是:

  1. Executors的静态方法提供的线程池默认使用无解的阻塞队列,如果提交的计算任务过多,有存在OOM的风险。
  2. 不能设置任务拒绝策略。
  3. 不能指定线程工厂ThreadFactory

在《Java并发编程实战》这本书中,作者描述了使用线程池的最佳实践:

  1. 使用ThreadPoolExecutor创建线程池对象

  2. 针对业务估算线程池中线程数量,线程数量计算公式如下:

  3. 使用自定义的ThreadFactory,为创建的线程设置有意义的命名。

  4. 使用有界队列

  5. 为线程设置未捕获的异常处理器

  6. 设置线程池的拒绝策略

下面的代码使用ThreadPoolExecutor的构造函数创建了自定义的线程池:

import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) {
        // 线程数量
        int threadNum = Runtime.getRuntime().availableProcessors();

        // 任务队列
        BlockingQueue<Runnable> taskQueue = new ArrayBlockingQueue<>(1024);

        // 自定义线程池工厂
        CustomThreadFactory threadFactory = new CustomThreadFactory();

        // 自定义拒绝策略
        CustomRejectHandler rejectHandler = new CustomRejectHandler();

        // 使用ThreadPoolExecutor构造线程池对象
        ThreadPoolExecutor pool = new ThreadPoolExecutor(threadNum, threadNum, 5, TimeUnit.SECONDS, taskQueue, threadFactory, rejectHandler);
    }
}

/**
 * 自定义的拒绝处理器。当任务队列空间被占满时,再提交任务就执行拒绝逻辑。
 */
class CustomRejectHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 可以记录日志。或者将任务保存到其他地方,等任务队列有空时再执行。
        System.out.println("自定义拒绝行为");
    }
}

/**
 * 自定义的线程工厂。线程池创建线程时会调用线程工厂来产生一个线程对象
 */
class CustomThreadFactory implements ThreadFactory {

    private Thread.UncaughtExceptionHandler exceptionHandler = (thread, exception) -> {
        // 在这里处理线程抛出的未捕获的异常
        exception.printStackTrace();
    };

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        // 为线程设置有意义的名称
        t.setName("bizThread");

        // 为线程设置未捕获的异常处理器
        t.setUncaughtExceptionHandler(exceptionHandler);
        return t;
    }
}
posted @ 2021-02-21 21:36  陈玉林  阅读(143)  评论(0编辑  收藏  举报