为什么不建议使用Executors 类提供的线程池

线程池是一种管理和复用技术:是为了减少创建和销毁线程的开销,可以限制并发线程数量,防止资源耗尽,统一管理监控线程的状态和执行。

小tips:根据线程池的创建代码可知,当核心线程数没满时,新来的任务会重新创建一个线程来处理,即使前面创建的线程时空闲的;当核心线程数已满但核心线程有空闲时,新任务会被分配给空闲的核心线程执行。

线程销毁时最开始创建的核心线程一定会保留吗?

根据底层代码可知,在线程销毁时,是通过CAS的方式进行线程销毁的,没有区分哪些线程是核心线程哪些不是,也就是说线程销毁是通过竞争的方式来销毁,随机销毁,最后只保留核心线程数个线程就行。

2,异常任务出现时,线程如何处理?

tips:当一个任务出现了异常,代码会将当前执行任务的线程销毁掉,重新再创建一个新的线程?

默认情况下,线程池中的线程会捕获任务中的异常并继续运行。

• 异常传播可能会发生在调用方尝试获取任务结果时。

• 自定义异常处理可以通过线程池的配置或扩展来实现。

• 线程池的健壮性通常会保证线程池不会因为单个任务的异常而崩溃。

3,线程的销毁:

shutdown():把阻塞队列中的任务执行完才会销毁所有线程

shutdownNow():立即销毁所有线程,忽略阻塞队列中的任务。

如果再此时有新任务来,不会再创建线程(代码里有判断)

线程正在拿任务时 如果调用shutdown方法,线程还是会继续拿任务。否则就不拿了。

4,线程创建时机
  • JUC中的线程池创建线程是当有任务需要执行时才会创建
  • tomcat中的threadPoolExecutor线程池再创建时就会创建好核心线程数的线程数量。
问题:

1,Executors.newFixedThreadPool() 和 Executors.newSingleThreadExecutor() 内部使用的是无界的 LinkedBlockingQueue,使用无界队列可能导致内存溢出

2,Executors.newCachedThreadPool() 创建的线程池没有最大线程数限制,且线程空闲时间超过 60 秒后会被回收。如果任务提交速度过快,线程池会不断创建新线程,导致线程数量过多,从而引发 CPU 调度开销过大 或 系统资源耗尽。

3,Executors 提供的线程池方法隐藏了线程池的实现细节,开发者无法灵活配置参数(如队列大小、线程存活时间等)。

线程池的策略
固定大小线程池(Fixed Thread Pool)线程数量固定,核心线程数=最大线程数,任务队列满了会直接执行拒绝策略
缓存线程池(Cached Thread Pool可以无限增大,如果长时间未使用的线程会被回收,适用于处理大量短生命周期的任务场景。存储任务的队列是SynchronousQueue,队列容量为0,只负责任务传递,效率比较高
计划线程池(Scheduled Thread Pool定时/周期性的任务执行,实现方法有三种:1,定时执行一次就结束;2,设置第一次延迟执行时间,且可设置后续固定延迟时间执行任务(周期性);3,任务结束时间后,设置延迟的时间执行下一次任务(周期性)
单一线程池(Single Thread Executor只有一个线程执行任务,可以保证任务按顺序执行
ThreadPoolExecutor核心参数 设置
corePoolSize核心线程数量,被创建了就不会被销毁的数量(开始的时候线程为空,当有任务到来时创建,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建?)。
maximumPoolSize最大线程数,线程池允许创建的最大线程数(是在核心线程数创建满了,并且队列中业存满了的情况下才会再次创建线程数量至最大线程数(无界队列除外))。
keepAliveTime:超出 corePoolSize 后创建的线程存活时间(当超过核心线程数后,又没有线程任务执行,达到该存活时间后,停止该线程)。
unit:线程活动保持时间的单位,即 keepAliveTime 的时间单位
workQueue:保存等待执行的任务的队列(阻塞队列),当线程数达到核心线程数且此时有新任务到来就会被放进阻塞队列,如果使用了工作队列 SynchronousQueue(SynchronousQueue 不会存储任何元素),那么当任务数超过线程池的核心线程数时,该任务不会进入队列
threadFactory :设置创建线程的工厂,决定如何创建线程,可以设置线程的名字、优先级、守护状态
handler:任务无法执行时的处理器(即拒绝策略)通常包括抛出异常、静默失败、抛弃旧任务等几种策略

推荐方案

使用 ThreadPoolExecutor 手动创建线程池

import java.util.concurrent.*;

public class CustomThreadPoolExample {
    public static void main(String[] args) {
        int corePoolSize = 4; // 核心线程数
        int maximumPoolSize = 8; // 最大线程数
        long keepAliveTime = 60L; // 空闲线程存活时间
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100); // 有界队列
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy(); // 拒绝策略

        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            corePoolSize,
            maximumPoolSize,
            keepAliveTime,
            unit,
            workQueue,
            threadFactory,
            handler
        );

        // 提交任务
        for (int i = 0; i < 200; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("任务 " + taskId + " 正在运行,线程:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟耗时任务(不会释放锁)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值