Java线程池的使用

核心参数说明

参数名原注释翻译
corePoolSizethe number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set线程中线程的数量,即使他们是空闲的,除非设置了核心线程存活时间
maximumPoolSizethe maximum number of threads to allow in the pool线程池中最大的线程数量,当核心线程不够时,会创建临时线程
keepAliveTimewhen the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.当存在临时线程时,临时线程在没有接受到任务时,存活的最大时间
unitthe time unit for the keepAliveTime argument时间单位
workQueuethe queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.用来存放任务的队列
threadFactory the factory to use when the executor creates a new thread创建线程的工厂
handlerthe handler to use when execution is blocked because the thread bounds and queue capacities are reached当核心线程在忙,等待队列也满了之后,如果还有任务进来的处理策略,此处为默认的策略

演示代码

package thread;

import java.util.concurrent.*;

/**
 * @author micro.cloud.fly
 * @date 2022/7/5 5:07 下午
 * @desc
 */
public class ThreadPoolDemo {
    public static void main(String[] args) {

        ExecutorService pool=new ThreadPoolExecutor(
                3,//核心线程,永远存活的线程
                5,//最大线程数量,表示还可能会创建两个临时线程
        6,//临时线程空闲6秒后,就会被消除
        TimeUnit.SECONDS,//临时线程存活的时间单位
                //等待队列,如果3个核心线程在忙,但是等待队列没有满,那么就不会创建临时线程
        new ArrayBlockingQueue<>(5),
                Executors.defaultThreadFactory(),//线程的创建工厂
                当核心线程在忙,等待队列也满了之后,如果还有任务进来的处理策略,此处为默认的策略
        new ThreadPoolExecutor.AbortPolicy()
        );
        //2、给任务线程池处理。
        Runnable target=new MuRunnable();
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);

        pool.execute(target);
        pool.execute(target);
        pool.execute(target) ;
        pool.execute(target);
        pool.execute(target);
        //此时核心线程在忙,等待队列也满了,此时才会创建临时线程
        pool.execute(target);
        pool.execute(target);
        //此时核心线程在忙,临时线程也在忙,等待队列也满了,如果后续再有队列进来,那么就会被拒绝
        // 不创建,拒绝策略被触发!!!
         pool.execute(target);
    }
}

创建线程池的其他方法

方法名称说明
public static ExecutorService newCachedThreadPool()线程数量随着任务的增加而增加,如果线程任务执行完毕切空闲了一段时间则会被回收掉
public static ExecutorService newFixedThreadPool(int nThreads)创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个 新的线程来替代它
public static ExecutorService newSingleThreadExecutor()创建之有一个线程的线程池对象,如果该线程出现异常而终结,那么线程池会补充一个新的线程
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建一个线程池,可以实现在给定的延迟时间后运行任务,或者定期执行任务

Executors使用可能存在的陷阱

大型并发系统环境中使用Executors如果不注意可能会出现系统风险。

方法名称存在问题
public static ExecutorService newFixedThreadPool(int nThreads)允许请求的任务队列长度是IntegerMAXVALUE,可能出现OOM 错误(java.lang.OutOfMemoryError)
public static ExecutorService newSingleThreadExecutor()允许请求的任务队列长度是IntegerMAXVALUE,可能出现OOM 错误(java.lang.OutOfMemoryError)
public static ExecutorService newCachedThreadPool()创建的线程数量最大上限是Integer.MAXVALUE,线程数可能会随着任务1:1增长,也可能出现OOM错误
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)(iava.lang.OutOfMemoryError)

阿里巴巴Java开发手册

【强制】 线程池不允许使用 Executors去创建,而是通过ThreadPoolExecutor的方式,这样
的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors返回的线程池对象的弊端如下:

  1. FixedThreadPool和SingleThreadPool:
    允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致00M。
    2.CachedThreadPool和ScheduledThreadPool:
    允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致00M。

线程的状态以及切换

在这里插入图片描述

<think>好的,我需要回答用户关于如何在Java使用线程池的问题,包括示例代码和最佳实践。首先,我应该回顾用户提供的引用内容,看看有没有相关的信息可以利用。 根据引用[1],提到了Java线程池使用实例、最佳实践以及代码示例。引用[2]讨论了为什么使用线程池、如何使用以及遇到的坑。引用[3]则集中在最佳实践和异常处理方面。这些引用应该能提供足够的信息来构建回答。 首先,我需要解释线程池的基本概念和为什么要使用线程池,比如资源复用、控制并发数、管理线程生命周期等。然后,介绍Java中创建线程池的方法,特别是通过Executors工厂类提供的几种常见线程池类型,比如FixedThreadPool、CachedThreadPool、SingleThreadExecutor等,但也要提到推荐直接使用ThreadPoolExecutor来创建,以便更灵活地控制参数,避免资源耗尽的风险,这点在引用[3]中有提到。 接下来,给出一个示例代码。根据引用[1]中的示例,可能需要展示如何通过ThreadPoolExecutor来创建线程池,设置核心线程数、最大线程数、队列容量等参数,并演示如何提交任务。同时,需要强调在阿里巴巴开发规范中推荐手动创建线程池,而不是使用Executors,这点可能来自引用[3]中的最佳实践。 然后,讨论最佳实践,比如合理配置线程数、使用有界队列、处理未捕获异常、正确关闭线程池等。这些内容在引用[3]中有涉及,比如异常处理和分析的重要性,以及关闭线程池的方法。 此外,要注意线程池的任务拒绝策略,如AbortPolicy、CallerRunsPolicy等,并说明在不同场景下如何选择合适的策略。这部分可能需要结合引用[2]中提到的使用过程中遇到的坑。 最后,生成相关问题,可能包括线程池的参数配置、不同线程池类型的区别、如何监控线程池状态、常见的线程池问题排查等,确保问题与用户查询内容相关,并帮助深化理解。 需要确保回答结构清晰,分步骤说明,代码正确,并且引用正确的位置。例如,在提到线程池参数配置时,引用[3]中的最佳实践;在提到任务拒绝策略时,引用[2]中的实际应用经验。 现在需要将以上思考整理成中文回答,确保符合用户要求的格式,使用正确的LaTeX语法,并在适当的位置添加引用标识。</think>### 如何在Java使用线程池? #### 1. **线程池的作用与优势** - **资源复用**:避免频繁创建/销毁线程,提升性能[^2]。 - **控制并发**:通过核心线程数、最大线程数限制资源占用[^3]。 - **任务管理**:使用队列缓冲任务,支持拒绝策略处理过载[^1]。 #### 2. **创建线程池** Java推荐通过`ThreadPoolExecutor`手动配置参数(而非`Executors`工厂类,避免潜在风险)[^3]: ```java int corePoolSize = 5; // 核心线程数 int maxPoolSize = 10; // 最大线程数 long keepAliveTime = 60L; // 空闲线程存活时间(秒) BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100); // 有界队列 ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.AbortPolicy() // 默认拒绝策略:直接抛出异常 ); ``` #### 3. **提交任务** - 使用`execute()`提交`Runnable`任务: ```java executor.execute(() -> { System.out.println("Task executed by " + Thread.currentThread().getName()); }); ``` - 使用`submit()`提交`Callable`任务(可获取返回值): ```java Future<String> future = executor.submit(() -> { return "Result from thread " + Thread.currentThread().getName(); }); System.out.println(future.get()); // 阻塞获取结果 ``` #### 4. **最佳实践** - **参数配置**: - CPU密集型任务:核心线程数 ≈ CPU核心数[^3]。 - I/O密集型任务:核心线程数可适当增加(如2倍CPU核心数)。 - 使用有界队列避免内存溢出[^3]。 - **异常处理**: ```java executor.setRejectedExecutionHandler((r, executor) -> { // 自定义拒绝策略,如记录日志或降级处理 }); // 任务内捕获异常 executor.execute(() -> { try { // 业务逻辑 } catch (Exception e) { // 记录异常 } }); ``` - **关闭线程池**: ```java executor.shutdown(); // 等待已提交任务完成 // executor.shutdownNow(); // 立即终止所有任务(慎用) ``` #### 5. **常用线程池类型** - **FixedThreadPool**:固定线程数,适用于负载较重的场景。 ```java ExecutorService fixedPool = Executors.newFixedThreadPool(5); ``` - **CachedThreadPool**:弹性线程数,适合短时异步任务[^1]。 - **ScheduledThreadPool**:支持定时/周期性任务。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

micro_cloud_fly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值