线程池参数以及运行过程

public class ThreadPool {
public static ExecutorService getPool(String poolName){
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat(poolName + “-%d”).build();
//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 100,
60000L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(10), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
return pool;
}

public static void main(String[] args) throws Exception{
    ExecutorService pool = getPool("aa");
    for (int i=0;i<2000;++i){
        pool.submit(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                Thread.sleep(10000000L);
            }
        });
    }
    pool.shutdown();
}

}
我建了一个核心线程为5,最大线程数为100,线程存活时间为60000单位是毫秒(这个线程后面会说到),一个长度为10的工作队列,线程工厂,线程策略为拒绝的策略。

1.当我们for循环第一次时,这时线程工厂会创建一个新的线程,这个线程为核心线程,
2.当第6次时也就是核心线程满了,这时会把任务放到工作队列,当工作队列也满了,这时线程工厂会创建新的线程,新线程执行的任务是新加的任务并不是从工作队列取的,当最大线程也满了,再进来任务则执行我们传入的拒绝策略,抛出异常。
3.当线程达最大线程之间时,如果没有任务进来,且任务队列有任务,当线程执行完任务会去任务队列取任务执行,当任务执行完且没有新任务进来,线程会根据配置的时间慢慢降低到核心线程数(线程存活时间就是针对这类核心线程到最大线程之间的这些普通线程的)
4.如果线程降到核心线程数和最大线程数之间,如果新进来任务,如果线程空闲着(设置了60000ms,线程并不会立即销毁)那么线程直接执行新进来的任务,如果没有空闲的则任务加入队列,队列满了再创建线程执行新进的任务。

总结:
1.任务进来先创建核心线程,核心线程满了放入队列
2.队列满了创建普通线程
3.线程满了并且队列满了执行reject策略
4.无任务时普通线程会根据超时时间慢慢降到核心线程数,此过程中如果有任务进来,空闲线程去执行任务,线程都不空闲放入队列,重复步骤2
5.所有任务执行完,线程数降到核心线程数
ps:核心线程并不是指某几个特定线程,只是一个概念。

### Java 线程池核心参数详解 Java 线程池核心参数定义了其行为模式和性能表现。以下是这些参数的具体解释及其作用: #### 1. **corePoolSize** `corePoolSize` 是线程池中保持的最小线程数,即使它们处于空闲状态。当提交的任务数量超过 `corePoolSize` 并且任务队列已满时,线程池会创建新的线程来处理任务[^4]。 ```java int corePoolSize = Runtime.getRuntime().availableProcessors(); // 示例:基于 CPU 数量设定 ``` #### 2. **maximumPoolSize** `maximumPoolSize` 表示线程池中允许的最大线程数。如果当前运行线程数达到此上限,则新任务会被拒绝并触发拒绝策略[^3]。 ```java int maximumPoolSize = Integer.MAX_VALUE; // 默认情况下最大值非常大 ``` #### 3. **keepAliveTime** `keepAliveTime` 定义了线程池中的空闲线程等待新任务的时间长度。一旦超出这个时间,多余的线程将会被销毁,直到线程总数降至 `corePoolSize`[^1]。 ```java long keepAliveTime = 60L; // 单位通常为秒 ``` #### 4. **workQueue** 工作队列用于保存待执行的任务对象。不同的队列类型会影响线程池的行为,例如: - `ArrayBlockingQueue`: 有界阻塞队列。 - `LinkedBlockingQueue`: 无界阻塞队列(理论上)。 - `SynchronousQueue`: 不存储元素的队列,直接将任务交给可用线程执行[^5]。 ```java BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(); ``` #### 5. **RejectedExecutionHandler** 当线程池无法再接受新任务时(即达到了 `maximumPoolSize` 和队列容量),会调用拒绝策略处理器。常用的拒绝策略包括抛出异常、丢弃任务或由调用者自行执行任务。 ```java ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, new ThreadPoolExecutor.AbortPolicy() // 使用默认拒绝策略 ); ``` --- ### 配置与使用场景分析 根据任务特性和系统资源的不同,可以选择合适的线程池配置方案: #### 1. **CPU 密集型任务** 对于计算密集型任务,建议将线程数设置为 `(CPU 核心数 + 1)` 左右,以充分利用 CPU 资源而不过度竞争。 #### 2. **I/O 密集型任务** 由于 I/O 操作会导致大量线程挂起,因此需要更多的线程来维持高并发能力。推荐公式为 `N * (W / R)`,其中 N 是 CPU 核心数,R 是每秒完成的任务数,W 是平均每个任务的耗时[^2]。 #### 3. **混合型任务** 针对既包含计算又涉及网络通信的情况,可以根据实际测试结果动态调整线程池大小,并结合异步框架减少阻塞性操作的影响。 --- ### 实际应用中的注意事项 为了确保线程池的安全性和高效性,在设计阶段需注意以下几点: - 设置合理的队列容量,防止因任务堆积而导致 OOM 错误。 - 对可能出现异常的任务进行捕获,以免影响整个线程池的工作流。 - 利用工具类方法监控线程池状态,及时发现潜在瓶颈问题。 --- ### 示例代码 下面展示了一个简单的自定义线程池实例化过程: ```java import java.util.concurrent.*; public class CustomThreadPool { public static void main(String[] args) { int corePoolSize = 2; int maxPoolSize = 4; long keepAliveTime = 10; BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(3); ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.CallerRunsPolicy() ); for(int i=0;i<7;i++) { final int taskNum = i; executor.execute(() -> System.out.println("Running Task " + taskNum)); } executor.shutdown(); } } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值