• java多线程 ThreadPoolExecutor 策略的坑


       无论是使用jdk的线程池ThreadPoolExecutor 还是spring的线程池ThreadPoolTaskExecutor 都会使用到一个阻塞队列来进行存储线程任务。

       当线程不够用时,则将后续的任务暂存到 阻塞队列中,等待有空闲线程来进行。

      当这个阻塞队列满了的时候,会出现两种情况

       正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;

       正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会通过一个策略进行对后续的任务进行处理。

    四种策略

    ThreadPoolExecutor.AbortPolicy()  抛出java.util.concurrent.RejectedExecutionException异常 
    ThreadPoolExecutor.CallerRunsPolicy() 重试添加当前的任务,他会自动重复调用execute()方法 
    ThreadPoolExecutor.DiscardOldestPolicy() 抛弃旧的任务 
    ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务 

    其他很容易看出来,最近踩了一个ThreadPoolExecutor.CallerRunsPolicy()的坑。

    情景是这样的:我需要通过线程进行创建长连接,当开启了15个线程的是,线程池最大即达到了maximumPoolSize的数量的时候,继续增大请求量,会无缘无故的多出来

    一个长连接,由于有负载均衡,导致了很多请求无法从长连接中得到。

    经过很长时间的测试,最终发现了是ThreadPoolExecutor.CallerRunsPolicy()策略导致的。

    这个测试是当你的线程数达到最大,阻塞队列也满了的时候,之后的任务会强制先执行,但是没有了线程谁来执行呢,这个策略会强制中断主线程进行执行这个任务。

    即是说,当我的量上来,线程池不够用的时候,中断了我的主线程,主线程没有长连接,就建立了一个新的长连接,那边进行了负载均衡,但是这边不会在进行主线程了,

    导致很多请求接收不到。

    假设队列大小为 10,corePoolSize 为 3,maximumPoolSize 为 6,那么当加入 20 个任务时,执行的顺序就是这样的:首先执行任务 1、2、3,然后任务 4~13 被放入队列。这时候队列满了,任务 14、15、16 会被马上执行,最终顺序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。

    踩坑完毕

    最终做法:

    换成ThreadPoolExecutor.DiscardPolicy()策略,还是从已经建立的连接中进行 的到请求,不要继续创建连接。

  • 相关阅读:
    setjmp和longjmp函数使用详解
    一文搞懂HMM(隐马尔可夫模型)
    Qt多工程多目录的编译案例
    HTML中Id和Name的区别
    字符识别中的图像归一化算法
    QT工程pro设置实践(with QtCreator)----非弄的像VS一样才顺手?
    暗通道优先的图像去雾算法
    callback用法简介
    ansible 批量部署准备工作
    MySQL高级管理
  • 原文地址:https://www.cnblogs.com/lic309/p/4564507.html
Copyright © 2020-2023  润新知