线程池

本文详细介绍了Java线程池的工作原理及其参数配置,包括核心线程数、最大线程数、存活时间、任务队列和拒绝策略等。通过示例展示了如何创建线程池,并分析了如何根据CPU密集型和IO密集型任务来合理设置线程池参数。此外,还讨论了不同类型的阻塞队列选择,并强调了使用有界队列对系统稳定性的重要性。

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

线程池

线程池使用

public static void main(String[] args) {
    /**
     * @param corePoolSize 当前CPU核数
     * @param maximumPoolSize 最大线程数量  我的电脑为4核(4+1) 既核数+1
     * @param keepAliveTime 存活时间,就是空闲时间 3秒
     * @param unit  秒
     * @param workQueue 对列,对列长队设置为3个长度
     * @param threadFactory 默认工厂Executors.defaultThreadFactory()
     * @param handler 策略 new ThreadPoolExecutor.AbortPolicy() 对列满了以后直接拒绝,抛出异常:RejectedExecutionException
     */
    System.out.println("当前电脑为" + Runtime.getRuntime().availableProcessors()+"核");
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
            Runtime.getRuntime().availableProcessors() + 1,
            3,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(3),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.CallerRunsPolicy());
    // 线程执行
    try {
        for (int i = 0; i < 10; i++) {
            threadPool.execute(() -> {
                log.info("Executors 创建线程池的方式实现多线程.......");
                // 业务代码执行
                int j = 100 / 3;
                log.info("业务代码执行结果:{}", j);
            });
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //线程池用完,关闭线程池
        threadPool.shutdown();
    }
}

参数解释

/**
 * @param corePoolSize    线程池核心线程数,初始化线程池时候,会创建核心线程等待状态,核心线程不会被销毁,提供线程的复用;
 * @param maximumPoolSize 最大线程数;核心线程用完了,必须新建线程执行任务,但是新建的线程不能超过最大线程数;
 * @param keepAliveTime   程存活时间,除了核心线程以为(maximumPoolSize- corePoolSize)的线程存活时间;当线程处于空闲状态,他可以活多久;
 * @param unit            存活时间单位
 * @param workQueue       任务阻塞队列,任务可能会很多,线程就那么几个,因此可以把多余的任务放入队列进行缓冲,队列采用 FIFO 的,等待线程空闲,再从队列取出任务执行;
 * @param threadFactory   线程工厂 默认使用的是 Executors.defaultThreadFactory() 用来创建线程的,一般使用默认即可;
 * @param handler         线程池拒绝策略线程池核心线程数,最大线程数,等待队列:
 *                        四种拒绝策略:
 *                        (1)、AbortPolicy : 新任务直接被拒绝,抛出异常:RejectedExecutionException;
 *                        (2)、DisCardPolicy: 队列满了,新任务忽略不执行,直接丢弃,不会抛出异常
 *                        (3)、DisCardOldestPolicy: 队列满了,新任务尝试和等待最久的线程竞争,也不会抛出异常;抛弃任务队列中等待最久任务,新任务直接添加到队列中
 *                        (4)、CallerRunsPolicy: 新任务来临后,直接使用调用者所在线程执行任务即可
 */
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler);

如何合理设置线程

合理配置线程相关的参数: 核心线程数,最大线程数
设置线程系线程数的数量: 根据业务类型进行设置(cpu 密集型,Io 密集型)
cpu 密集型:
     所有任务都在内存中执行:没有磁盘的读写: 建议线程池最大数量设置为:
     cpu 核心数量+1
IO 密集型型:
     所有任务(大量磁盘读写任务):如果有 IO 操作,cpu 此时处于空闲状态, 最大线程数应该设置:
     2*N+1
最大线程数设置公式:
     最大线程数 = (任务执行时间 / 任务 cpu 时间)*N

如何选择队列

如何使用队列
在 Java 并发编程中,使用线程池,还必须使用任务队列,让任务在队列中进行缓冲;可以线程执行防洪泄流的效果,提升线程池处理任务能力
通常在线程池中,使用的都是阻塞队列:
     存:队列满了,等待对列中元素被消费,有空闲位置在放入对列
     取:队列空的,阻塞等待,知道对列中有数据,在消费数据
基于 Java 一些队列实现特性:
     1、ArrayBlockingQueue : 基于数组实现的有界的阻塞队列 (有界的队列)
     2、LinkedBlockingQueue: 基于链表实现的有界阻塞队列 (有界的队列)
     3、PriorityBlockingQueue: 支持按照优先级排序的无界的阻塞的队列 (无界的队列)
     4、DelayQueue: 优先级实现的无界阻塞队列 (有界的队列)
     5、SynchronousQueue : 只存储一个元素,如果这个元素没有被消费,不能在向里面存储元素
     6、LinkedTransferQueue: 基于链表实现的无界的阻塞队列 (无界的队列)
     7、LinkedBlockingDeque: 基于链表实现的双向的无界阻塞的队列 (无界的队列)
 如何选择?
     建议使用有界队列
     有界队列能增加系统的稳定性,根据需求设置大一些(可控设置);
     如果设置为无界队列,遇到不可控的因素,可能会导致队列中的任务越来越多,出现 OOM,撑爆整个系统;

异常信息

如果抱錯信息为这个,
加入你的电脑核心数为4核,那么 maximumPoolSize = 4+1,如果小于了则会抛出一下异常
Exception in thread "main" java.lang.IllegalArgumentException
    at java.util.concurrent.ThreadPoolExecutor.<init>(ThreadPoolExecutor.java:1314)
    at com.kkb.cubemall.thirdparty.demo.ThreadPoolDemo.main(ThreadPoolDemo.java:27)

所有代码

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

@Slf4j
public class ThreadPoolDemo {

    public static void main(String[] args) {
        /**
         * @param corePoolSize 当前CPU核数
         * @param maximumPoolSize 最大线程数量  我的电脑为4核(4+1) 既核数+1
         * @param keepAliveTime 存活时间,就是空闲时间 3秒
         * @param unit  秒
         * @param workQueue 对列,对列长队设置为3个长度
         * @param threadFactory 默认工厂Executors.defaultThreadFactory()
         * @param handler 策略 new ThreadPoolExecutor.AbortPolicy() 对列满了以后直接拒绝,抛出异常:RejectedExecutionException
         */
        System.out.println("当前电脑为" + Runtime.getRuntime().availableProcessors() + "核");

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
                Runtime.getRuntime().availableProcessors() + 1,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        // 线程执行
        try {
            for (int i = 0; i < 10; i++) {
                threadPool.execute(() -> {
                    log.info("Executors 创建线程池的方式实现多线程.......");
                    // 业务代码执行
                    int j = 100 / 3;
                    log.info("业务代码执行结果:{}", j);
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完,关闭线程池
            threadPool.shutdown();

        }
    }

    /**
     * 如果抱錯信息为这个,
     * 加入你的电脑核心数为4核,那么 maximumPoolSize = 4+1,如果小于了则会抛出一下异常
     * Exception in thread "main" java.lang.IllegalArgumentException
     *      at java.util.concurrent.ThreadPoolExecutor.<init>(ThreadPoolExecutor.java:1314)
     *      at com.kkb.cubemall.thirdparty.demo.ThreadPoolDemo.main(ThreadPoolDemo.java:27)
     */

    /**
     * 合理配置线程相关的参数: 核心线程数,最大线程数
     * 设置线程系线程数的数量: 根据业务类型进行设置(cpu 密集型,Io 密集型)
     * cpu 密集型:
     *      所有任务都在内存中执行:没有磁盘的读写: 建议线程池最大数量设置为:
     *      cpu 核心数量+1
     * IO 密集型型:
     *      所有任务(大量磁盘读写任务):如果有 IO 操作,cpu 此时处于空闲状态, 最大线程数应该设置:
     *      2*N+1
     * 最大线程数设置公式:
     *      最大线程数 = (任务执行时间 / 任务 cpu 时间)*N
     */

    /**
     * 如何使用队列
     *      在 Java 并发编程中,使用线程池,还必须使用任务队列,让任务在队列中进行缓冲;可以线程执行防洪泄流的效果,提升线程池处理任务能力
     * 通常在线程池中,使用的都是阻塞队列:
     *      存:队列满了,等待对列中元素被消费,有空闲位置在放入对列
     *      取:队列空的,阻塞等待,知道对列中有数据,在消费数据
     * 基于 Java 一些队列实现特性:
     *      1、ArrayBlockingQueue : 基于数组实现的有界的阻塞队列 (有界的队列)
     *      2、LinkedBlockingQueue: 基于链表实现的有界阻塞队列 (有界的队列)
     *      3、PriorityBlockingQueue: 支持按照优先级排序的无界的阻塞的队列 (无界的队列)
     *      4、DelayQueue: 优先级实现的无界阻塞队列 (有界的队列)
     *      5、SynchronousQueue : 只存储一个元素,如果这个元素没有被消费,不能在向里面存储元素
     *      6、LinkedTransferQueue: 基于链表实现的无界的阻塞队列 (无界的队列)
     *      7、LinkedBlockingDeque: 基于链表实现的双向的无界阻塞的队列 (无界的队列)
     * 如何选择?
     *      建议使用有界队列
     *      有界队列能增加系统的稳定性,根据需求设置大一些(可控设置);
     *      如果设置为无界队列,遇到不可控的因素,可能会导致队列中的任务越来越多,出现 OOM,撑爆整个系统;
     */

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值