Java正确创建线程池方式

本文探讨了线程池的不同创建方式及其潜在问题,强调避免使用Executors创建线程池,并推荐使用ThreadPoolExecutor来精确控制线程池参数,以降低资源耗尽风险。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  PS:最近换工作,被问到多次线程池的问题 例如 线程池的几种实现方式,怎样创建一个线程池等等。也是前段时间阿里发布了Java代码约束工具,规定不建议使用Executors去直接创建线程,而是通过ThreadPoolExcutor的方式,规则如下:

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资激耗尽的风险。
说明:Executors各个方法的弊端:
1) newFixedThreadPoolfPnewSingleThreadExecutor:
主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至00M。
2) newCachedThreadPoolfPnewScheduledThreadPool:
主要问題是线程数最大数是Integer.MAX_VALUE,可能会创建数置非常多的线程,甚至00M。

Positive example 1:

//org.apache.commons.Iang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(l,
          new BasicThreadFactory.Builder().namingPattern(Mexample-schedule-pool-%d").daemon(true).build());
Positive example 2:

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat(Mdemo-pool-%d").build();
//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 200,
   0L, TimeUnit.MILLISECONDS,
   new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown() "/gracefully shutdown
Positive example 3:

<bean id="userThreadPoolM
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
	<property name=McorePoolSize" value="10M />
	<property name=MmaxPoolSize" value="100M />
	<property name=MqueueCapacity" value="2000M />

<property name=MthreadFactoryM value= threadFactory />
	<property name="rejectedExecutionHandlerM>
<ref local="rejectedExecutionHandler" />
</property>
</bean>
//in code
userThreadPool.execute(thread);

<think>嗯,用户想知道Java中如何创建线程池。首先,我需要回忆一下Java创建线程池的方法。记得Java提供了Executor框架,特别是ThreadPoolExecutor类,还有Executors工具类里的工厂方法。不过,用户可能更想知道具体的步骤和不同方式。 首先,我应该介绍Executors工具类,因为它是最简单的创建线程池方式。比如newFixedThreadPool、newCachedThreadPool这些方法。需要提到每种方法的特点,比如固定大小还是可缓存的。然后,可能还要提到为什么不推荐直接使用这些工厂方法,因为它们的参数可能不太灵活,或者在某些情况下会导致问题,比如newFixedThreadPool使用无界队列可能会内存溢出。 接下来,应该讲更高级的方式,直接使用ThreadPoolExecutor的构造函数。这样用户可以自定义核心线程数、最大线程数、存活时间、工作队列和拒绝策略。这里需要详细说明每个参数的作用,比如corePoolSize、maximumPoolSize,还有BlockingQueue的不同实现,比如ArrayBlockingQueue和LinkedBlockingQueue的区别,以及拒绝策略有哪些,比如AbortPolicy、CallerRunsPolicy等。 然后,可能需要举一个例子,比如用Executors创建一个固定大小的线程池,或者用ThreadPoolExecutor手动配置。代码示例会帮助用户理解,但要注意语法正确,比如正确导入包,处理异常等。 另外,用户可能不知道线程池的类型和适用场景。比如newCachedThreadPool适合短生命周期的异步任务,而newSingleThreadExecutor适合需要顺序执行的任务。同时,要提醒资源耗尽的风险,比如使用无界队列可能导致内存问题,所以推荐有界队列和合适的拒绝策略。 最后,可能需要提到Java 7引入的ForkJoinPool,用于分治任务,但可能用户的问题主要围绕传统线程池,所以简要提及即可。总结时强调根据需求选择创建方式,并注意参数配置和资源管理,避免常见问题。</think>在 Java创建线程池主要有以下两种方式,我们逐步分析实现步骤: 一、通过 `Executors` 工具类(快速创建) ```java // 1. 固定大小线程池 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); // 2. 可缓存线程池(自动扩容) ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); // 3. 单线程池(保证顺序执行) ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); // 4. 定时任务线程池 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); ``` *特点*:简单快捷,但缺乏精细控制(如队列长度、拒绝策略等) 二、通过 `ThreadPoolExecutor` 构造函数(推荐方式) ```java // 参数说明 int corePoolSize = 5; // 核心线程数 int maxPoolSize = 10; // 最大线程数 long keepAliveTime = 60L; // 空闲线程存活时间(秒) BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100); // 任务队列 RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略 ExecutorService customPool = new ThreadPoolExecutor( corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, Executors.defaultThreadFactory(), handler ); ``` 关键参数说明: 1. **corePoolSize**:线程池长期维持的核心线程数 2. **maximumPoolSize**:线程池最大线程容量 3. **keepAliveTime**:非核心线程空闲时的存活时间 4. **workQueue**: - `ArrayBlockingQueue`:有界队列 - `LinkedBlockingQueue`:无界队列(默认最大长度 Integer.MAX_VALUE) - `SynchronousQueue`:直接提交队列 5. **拒绝策略**: - AbortPolicy(默认):直接抛出 RejectedExecutionException - CallerRunsPolicy:由提交任务的线程直接执行 - DiscardPolicy:静默丢弃任务 - DiscardOldestPolicy:丢弃队列最前面的任务 三、使用建议 1. 推荐使用 `ThreadPoolExecutor` 构造函数,避免 `Executors` 的潜在问题 2. 根据业务场景选择队列类型: - CPU 密集型:建议使用有界队列 + 合理线程数(通常设置为 CPU 核心数 + 1) - IO 密集型:可适当增大线程池容量 3. 务必设置合理的拒绝策略,防止资源耗尽 4. 使用后必须调用 `shutdown()` 关闭线程池 示例完整代码: ```java public class ThreadPoolDemo { public static void main(String[] args) { // 创建线程池 ExecutorService pool = new ThreadPoolExecutor( 2, 5, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy() ); // 提交任务 for (int i = 0; i < 15; i++) { final int taskId = i; pool.execute(() -> { System.out.println("执行任务:" + taskId + ",线程:" + Thread.currentThread().getName()); }); } // 关闭线程池 pool.shutdown(); } } ``` 注意事项: 1. 避免使用无界队列(可能导致内存溢出) 2. 合理设置线程存活时间 3. 监控线程池状态(可通过重写 `beforeExecute()` 和 `afterExecute()` 方法) 4. 推荐使用有命名的线程工厂,便于问题排查
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值