ThreadPoolExecutor线程池简单分析

public class ThreadPoolTest {
    public static void main(String[] args) {
        //核心线程数
       int corePoolSize = 3;
       //最大线程数
       int maxPoolSize = 6;
       //超过核心线程数量的线程最大空闲时间
       long keepAliveTime = 2;
       //时间单位秒
       TimeUnit unit = TimeUnit.SECONDS;
       //创建工作队列,用于存放提交的等待执行任务
        BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(2);
        ThreadPoolExecutor threadPoolExecutor = null;
        try {
            //核心线程数,最大线程数,超过核心线程数线程空闲时间,单位,工作队列,拒绝策略
            threadPoolExecutor = new ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveTime,unit,blockingQueue,new ThreadPoolExecutor.AbortPolicy());
            //提交任务
            for (int i = 0; i < 8; i++) {
                int index = i+1;
                threadPoolExecutor.submit(() -> {
                    System.out.println("线程:" + index);
                    //模拟线程执行时间
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
                //线程提交完,线程睡一觉
                Thread.sleep(50);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /*
        运行结果分析:
        1.ThreadPool构造函数创建线程池
        2.for循环提交8个任务,(等于 最大线程数 + 队列等待数)
        3.通过threadPoolExecutor.submit 提交Runnable接口任务
        4.提交 1 的时候,由于当前线程正在执行的任务是0小于核心线程数(3),
        所以会新建一个线程来提交任务1
        5.提交2,3时候 当前正在执行的任务 小于等于核心线程数(3)
        所以都会新建一个线程来提交任务2,3
        6.当前线程池中正在执行的线程是3(线程执行是10s,所以3个新建的线程都会在执行)
        提交4的时候,如果新建线程来执行,执行的线程数就大于了核心线程数所以不能再新建线程,
        此时会把 任务4 放到队列等待
        7.队列的大小是2 任务5 也会放入队列等待
        8.提交任务6,此时队列已经满了,另外核心线程可执行线程数是3,这时就要判断线程池中
        执行的任务数是不是大于最大线程数(6)
        9.如果小于6,那么就会新建一个线程来执行任务6
        10.执行7,8的时候也要判断是不是大于最大线程数(6)
        11.此时6个任务都有线程在执行,那么队列中的任务 4,5什么时候执行
        12.当任务1执行完毕(10s后),线程1不会被销毁,而是获取队列中的任务4来执行
        13.当任务2执行完毕(10s后),线程2不会被销毁,而是获取队列中的任务5来执行
        上述流程可知:线程池中的线程执行完毕后不会立刻销毁,线程池中会保留核心线程数的线程,
        当队列中有任务等待或是新提交的任务,那么会通过线程池中已有的线程来执行任务,避免了
        线程频繁的创建和销毁,而大于核心线程数 小于最大线程数 创建的线程会在空闲时间后被回收


        线程池的拒绝策略:当线程池关闭或饱和的时候(达到最大线程数 队列已满),新提交的任务会被拒绝
        1.AbortPolicy(默认拒绝策略):拒绝任务时抛出异常 RejectedExecutionException
        2.CallerRunsPolicy:将被拒绝任务添加到线程池正在运行的线程中去执行,如果线程池关闭,任务被丢弃
        3.DiscardPolicy:丢弃任务但不抛出异常
        4.DiscardOldestPolicy:丢弃队列中等待时间最长的任务,并执行当前提交的任务。如果线程池关闭,认为丢弃


       线程池队列入队策略:
       1.直接传递:通过 SynchronousQueue 直接把任务传递给线程。
       如果当前没可用线程,尝试入队操作会失败,然后再创建一个新的线程。
       当处理可能具有内部依赖性的请求时,该策略会避免请求被锁定。
       直接传递通常需要无界的最大线程数(maximumPoolSize),避免拒绝新提交的任务。
       当任务持续到达的平均速度超过可处理的速度时,可能导致线程的无限增长。

       2.有界队列:当使用有限的最大线程数时,有界队列(如 ArrayBlockingQueue)可以防止资源耗尽,但是难以调整和控制。
       队列大小和线程池大小可以相互作用:使用大的队列和小的线程数可以减少CPU使用率、系统资源和上下文切换的开销,但是会导致吞吐量变低,
       如果任务频繁地阻塞(例如被I/O限制),系统就能为更多的线程调度执行时间。
       使用小的队列通常需要更多的线程数,这样可以最大化CPU使用率,但可能会需要更大的调度开销,从而降低吞吐量。

       3.无界队列:使用无界队列(如 LinkedBlockingQueue)作为等待队列,当所有的核心线程都在处理任务时, 新提交的任务都会进入队列等待。
       因此,不会有大于 corePoolSize 的线程会被创建(maximumPoolSize 也将失去作用)。
       这种策略适合每个任务都完全独立于其他任务的情况;例如网站服务器。这种类型的等待队列可以使瞬间爆发的高频请求变得平滑。
       当任务持续到达的平均速度超过可处理速度时,可能导致等待队列无限增长。


     */
}

运行结果:在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

会跑的葫芦怪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值