首页 > 其他分享 >线程池实现原理及实践

线程池实现原理及实践

时间:2024-10-22 17:52:37浏览次数:5  
标签:Executors 队列 实践 任务 线程 Executor 原理 ThreadPoolExecutor

线程池的总体设计


ThreadPoolExecutor实现的顶层接口是Executor,顶层接口Executor提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何创建线程,如何调度线程来执行任务,用户只需提供Runnable对象,将任务的运行逻辑提交到执行器(Executor)中,由Executor框架完成线程的调配和任务的执行部分。

ExecutorService接口增加了一些能力:

(1)扩充执行任务的能力,补充可以为一个或一批异步任务生成Future的方法;

(2)提供了管控线程池的方法,比如停止线程池的运行。

AbstractExecutorService则是上层的抽象类,将执行任务的流程串联了起来,保证下层的实现只需关注一个执行任务的方法即可。

ThreadPoolExecutor实现最复杂的运行部分,ThreadPoolExecutor将会一方面维护自身的生命周期,另一方面同时管理线程和任务,使两者良好的结合从而执行并行任务。

    public static void main(String[] args) {
        Executor executor = new Executor() {
            @Override
            public void execute(@NotNull Runnable command) {
                System.out.println("1");
                command.run();
            }
        };
        executor.execute(()-> System.out.println("1"));


        Executor e1 = c->{
            c.run();
        };
        e1.execute(()-> System.out.println("1"));
    }

线程池核心参数:

创建线程池:

是常用的几种方式:

1. ThreadPoolExecutor

最灵活的方式,可以通过自定义参数创建线程池。

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize, 
    maximumPoolSize, 
    keepAliveTime, 
    TimeUnit.SECONDS, 
    new LinkedBlockingQueue<Runnable>(),
    Executors.defaultThreadFactory(),
    new ThreadPoolExecutor.AbortPolicy()
);

2. Executors 工具类

Executors 提供了一些便捷的方法来创建常用的线程池类型:

  • 单线程池

    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    
  • 固定线程池(指定核心线程数):

    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads);
    
  • 可缓存线程池(线程数不限制,根据需要创建和回收线程):

    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    
  • 定时任务线程池(可以定期执行任务):

    ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(nThreads);
    

线程池线程执行执行机制

  1. 核心线程数未满
    • 如果当前活动线程数少于核心线程数(corePoolSize),线程池会创建新的线程来执行新提交的任务。
  2. 核心线程数满,但阻塞队列未满
    • 如果当前活动线程数已经达到核心线程数,而阻塞队列尚未满,新的任务会被添加到阻塞队列中,等待已有线程来处理。
  3. 阻塞队列满,最大线程数未满
    • 如果当前活动线程数达到核心线程数,且阻塞队列已满,线程池会创建新的线程来执行新提交的任务,前提是活动线程数未达到最大线程数(maximumPoolSize)。
  4. 拒绝策略
    • 如果当前活动线程数已经达到最大线程数,并且阻塞队列也已满,线程池会根据设置的拒绝策略来处理新提交的任务。常见的拒绝策略包括:
      • AbortPolicy:抛出 RejectedExecutionException(默认策略)。
      • CallerRunsPolicy:由调用者线程执行任务,阻塞调用线程。
      • DiscardPolicy:丢弃新提交的任务。
      • DiscardOldestPolicy:丢弃阻塞队列中最旧的任务,并尝试重新提交当前任务。

线程池在业务中的实践:

场景1:快速响应请求

描述:用户发起的实时请求,服务追求响应时间。比如说用户要查看一个商品的信息,那么我们需要将商品维度的一系列信息如商品的价格、优惠、库存、图片等等聚合起来,展示给用户。

分析:这种场景最重要的就是获取最大的响应速度,所以不应该设置队列去缓冲并发任务(new SynchronousQueue()),并且应该尽量调大corepoolsize和maximumpollsize

场景2:快速处理批量任务

描述:离线的大量计算任务,需要快速执行,但不追求立即响应。比如上游服务下发的一些任务。

分析:不需要瞬时的完成,而是关注如何使用有限的资源,尽可能在单位时间内处理更多的任务,也就是吞吐量优先的问题。所以应该设置队列去缓冲并发任务( new LinkedBlockingDeque<>(10000)),调整合适的corePoolSize去设置处理任务的线程数。在这里,设置的线程数过多可能还会引发线程上下文切换频繁的问题,也会降低处理任务的速度,降低吞吐量。

TIPS:

线程池的线程数量没有银弹,真正能并发的线程量=CPU核数,所以要注意当线程数量太大时,上下文的切换也会占用相当的资源

业务中也可以通过配置的方式动态配置线程池

标签:Executors,队列,实践,任务,线程,Executor,原理,ThreadPoolExecutor
From: https://www.cnblogs.com/awstan/p/18493383

相关文章

  • HarmonyOS ArkUI性能优化实践:长列表加载性能优化
    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(MaoistLearning)➤博客园地址:为敢技术(https://www.cnblogs.com/strengthen/ )➤GitHub地址:https://github.com/strengthen➤原文地址:https://www.cnblogs.com/strengthen/p/......
  • 2024秋软工实践 爱码单车队展示与选题报告
    作业所属课程班级链接作业要求作业要求链接作业的目标开发一个基于LLM大模型接口的软件,为传统的软件赋予全新的体验和功能。团队名称爱码单车队成员1102201542--曾庆徽成员2102201211--池家益成员3102201302--毛震成员4102201420--林传昊成......
  • Java 中的垃圾收集器有哪些,它们的工作原理是什么?
    在Java中,垃圾收集(GC)是自动内存管理的核心部分,它帮助开发者免于手动管理内存分配和回收,提升了开发效率和应用性能。Java中的主要垃圾收集器包括SerialGC、ParallelGC、CMS(ConcurrentMarkSweep)GC、G1(Garbage-First)GC,以及最新的ZGC(ZGarbageCollector)和Shenand......
  • 流体世界的眼睛,流量传感器工作原理
    我们能看见听见并感受到这个丰富多彩的世界,依赖眼睛、耳朵以及皮肤这些器官。在管道密布的流体世界,也有自己的各种器官,像压力传感器、光线传感器、温度传感器,以及我们这期的主题——流量传感器。流量传感器可能离你很远,在郊区的化工厂,在万米高空的飞机,甚至大气层外的空间站......
  • 【架构与设计】常见微服务分层架构的区别和落地实践
    作者:京东科技康志兴前言从强调内外隔离的六边形架构,逐渐发展衍生出的层层递进、注重领域模型的洋葱架构,再到和DDD完美契合的整洁架构。架构风格的不断演进,其实就是为了适应软件需求越来越复杂的特点。可以看到,越现代的架构风格越倾向于清晰的职责定位,且让领域模型成为架构的......
  • Explain详解与索引优化最佳实践
    Mysql安装文档参考:http://note.youdao.com/noteshare?id=12bab3ad6bde2dc0db4158df1b23b7cd&sub=69BD07746CCF4F7DA94CCFB1C4E399E8Explain工具介绍使用EXPLAIN关键字可以模拟优化器执行SQL语句,分析你的查询语句或是结构的性能瓶颈 在select语句之前增加explain关键字......
  • Amazon Q Developer 实践:零基础创建贪吃蛇游戏
    本文探讨了如何使用AmazonQDeveloper根据结构化的提示词,直接生成一个贪吃蛇游戏原型,并剖析了其背后人工智能的思考和迭代完善过程,展示了人工智能能快速进行游戏原型创作的巨大潜力。原文出处来自作者于2024年9月在community.aws发表的技术文章:“FromConcepttoPlaya......
  • java中的锁及实现原理
    重入锁ReentrantLock重人锁ReentrantLock,顾名思义,就是支持重进人的锁,它表示该锁能够支持一个线程对资源的重复加锁。除此之外,该锁的还支持获取锁时的公平和非公平性选择。ReentrantLock虽然没能像synchronized关键字一样支持隐式的重进人,但是在调lock()方法时,已经获取到锁的线......
  • Unity Shader深度图的应用,手把手教你写出可以正确计算并且渲染出二次元角色边缘光的着
    梦开始的地方相信大家看番的时候,都注意到了,很多时候,在角色周围有一圈光晕旧版《魔术快斗》剧照《新蔷薇少女》剧照 我们将这种光晕,称之为边缘光边缘光是描边的一种,动画师之所以加入边缘光,是为了凸现角色轮廓,使得角色区别于背景不少游戏也有着这种边缘光游戏《鸣潮》......
  • 11-案例:多线程版用户聊天程序
    1.多线程版用户群聊程序的_多用户聊天运行结果2.多线程版用户群聊程序的_服务端代码3.多线程版用户群聊程序的_客户端代码4.多线程版用户群聊程序的_双用户聊天运行结果5.多线程版用户群聊程序的_双用户聊天运行服务端代码6.多线程版用户群聊程序的_双用户聊天运行客户端代码......