码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 并发-Java中的线程池


    Java中的线程池

    好处:

    • 降低资源消耗
    • 提高响应速度
    • 提高线程的可管理性

    线程池的实现原理

    • 处理流程
      • 线程池判断核心线程池里是否都在执行任务,如果不是,则创建一个新的工作中线程来执行任务,如果核心线程池里的线程都在执行任务,则进入下一个流程
      • 线程池判断工作中队列是否已经满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里,如果工作队列满了,则进入下个流程
      • 线程池判断线程池的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务,如果已经满了,则交给饱和策略来处理这个任务

    在这里插入图片描述

    • ThreadPoolExecutor执行execute方法的4种情况

      • 如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(需获取全局锁)
      • 如果运行线程等于或多于corePoolSize,则将任务加入BlockingQueue
      • 如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(获取全局锁)
      • 如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExcutionHandler.rejectedExecution()方法.
    • 工作线程:线程池创建线程时,会将线程封装成工作线程Worker,Worker在执行完任务后,还会循环获取工作队列里的任务来执行

    • 线程池中的线程执行任务分两种

      • 在execute()方法中创建一个线程时,会让这个线程执行当前任务
      • 这个线程执行完任务后,会反复从BlockingQueue获取任务来执行

    线程池的使用

    线程池的创建
    new ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • corePoolSize: 线程池基本大小,提交一个任务到线程池时,会创建一个线程来执行任务,及时其他空闲的能执行,也要创建,等需要执行的任务数大于线程池基本大小时就不再创建。

      • 如果调用了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有基本线程。
    • maximumPoolSize:线程池最大数量,线程池允许创建的最大线程数。如果队列满了,并已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。如果使用了无界任务队列这个参数没什么效果。

    • keepAliveTime:线程活动保持时间,线程池的工作线程空闲后,保持的存活时间,如果任务很多,并且每个任务执行的时间比较短,可以调大时间 ,提高线程利用率。

    • TimeUnit unit:线程活动保持时间的单位,天,小时,分钟,毫秒,微秒,纳秒

    • BlockingQueue workQueue:任务队列,用于保存等待执行的任务的阻塞队列

      • ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按FIFO原则对元素进行排序
      • LinkedBlockingQueue:一个基于链表结构的阻塞队列,FIFO排序,吞吐量高于ArrayBlockingQueue
      • SynchronousQueueu:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常高于LinkedBlockingQueue
      • PriorityBlockingQueue:一个具有优先级的无限阻塞队列
    • ThreadFactory threadFactory:用于创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

      • new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build();
        
        • 1
    • RejectedExecutionHandler handler :饱和策略:当队列和线程池都满了,说明线程池处于饱和状态,采用一种策略处理提交的新任务。默认AbortPolicy

    • AbortPolicy:直接抛出异常

    • CallerRunsPolicy:只用调用者所在线程来运行任务

    • DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务

    • DiscardPolicy:不处理,丢弃掉

    • 自定义处理策略

    向线程池提交任务
    • execute()方法:用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功

      • threadsPool.execute(new Runnable(){
        	@Override
        	public void run(){
        	
        	}
        })
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
    • submit()方法:用于提交需要返回值的任务,线程池会返回一个future类型对象,通过这个对象可以判断任务是否执行成功,

      • 通过future的get方法获取返回值

      • get()方法会阻塞当前线程直到任务完成。

      • get(long timeout,TimeUnit unit)会阻塞当前线程一段时间后立即返回,可能没执行完

      • Future future = executor.submit(harReturnValuetask);
        try{
        	Object s = future.get();
        }catch(){
        
        }finally{
        	executor.shutdown();
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        关闭线程池

        调用线程池的shutdown或shutdownNow方法关闭线程池,原理:遍历线程池中的工作线程,然后逐个调用线程的interrupt方法中断线程,所以无法响应中断的任务可能永远无法终止。

        • shutdownNow首先将线程池状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表
        • shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。

        通常调用shutdown方法来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow方法。

        合理地配置线程池

        分析:

        • 任务性质:

          • CPU密集型任务,IO密集型任务和混合型任务

            • CPU秘籍型任务应配置尽可能小的线程,如配置N(cpu)+1个线程的线程池

            • IO密集型任务并不是一直在执行任务,应配置尽可能多的线程,2*N(cpu)

            • 混合型任务,拆分成一个cpu密集任务一个io密集任务,如果任务执行时间相差太大,没必要分解

              • Runtime.getRuntime().availableProcessors()方法获取设备的CPU个数
                
                • 1
          • 任务的优先级:高,中和低

            • 可以使用优先级队列PriorityBlockingQueue来处理,可以让优先级高的任务先执行
          • 任务的执行时间:长,中和短

            • 交给不同规模的线程池来处理,或者使用优先级队列,让执行时间短的任务先执行
          • 任务的依赖性:是否依赖其他系统资源,如数据库连接。、

            • 等待时间越长,则cpu空闲时间就越长,线程数应该设置的越大,才能更好利用cpu
        • 建议使用有界队列

          • 有界队列能增加系统的稳定性和预警能力,可以根据需要设置大点
        线程池的监控

        监控属性

        • taskCount:线程池需要执行的任务数量
        • completedTaskCount:线程池在运行过程中已完成的任务数量,小于等于taskCount
        • largestPoolSize:线程池里创建过的最大线程数量,通过这个数据可以知道线程池是否曾经满过,如该数值等于线程池的最大大小,则表示线程池曾满过
        • getPoolSize:线程池的线程数量,如果线程池不销毁的话,线程池里的线程不会自动销毁,所以这个大小只增不减
        • getActiveCount:获取活动的线程数
      • 相关阅读:
        Tableau2——折线图,饼图
        ansible-第二天
        KNN算法分类问题实现介绍和使用
        好奇喵 | Tor浏览器——如何拥有一颗洋葱并使用
        操作系统文件使用磁盘的实现---20
        【JavaSe笔记】——类和对象、this引用、构造方法、封装、static、代码块
        web网页设计期末课程大作业:美食餐饮文化主题网站设计——HTML+CSS+JavaScript美食餐厅网站设计与实现 11页面
        【ES实战】ES上的安全性运行方式
        16-bit 内置基准模数转换器:MS1100
        给女朋友的微信专属推送
      • 原文地址:https://blog.csdn.net/weixin_39795049/article/details/132724466
        • 最新文章
        • 攻防演习之三天拿下官网站群
          数据安全治理学习——前期安全规划和安全管理体系建设
          企业安全 | 企业内一次钓鱼演练准备过程
          内网渗透测试 | Kerberos协议及其部分攻击手法
          0day的产生 | 不懂代码的"代码审计"
          安装scrcpy-client模块av模块异常,环境问题解决方案
          leetcode hot100【LeetCode 279. 完全平方数】java实现
          OpenWrt下安装Mosquitto
          AnatoMask论文汇总
          【AI日记】24.11.01 LangChain、openai api和github copilot
        • 热门文章
        • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
          奉劝各位学弟学妹们,该打造你的技术影响力了!
          五年了,我在 CSDN 的两个一百万。
          Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
          面试官都震惊,你这网络基础可以啊!
          你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
          心情不好的时候,用 Python 画棵樱花树送给自己吧
          通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
          13 万字 C 语言从入门到精通保姆级教程2021 年版
          10行代码集2000张美女图,Python爬虫120例,再上征途
        Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
        正则表达式工具 cron表达式工具 密码生成工具

        京公网安备 11010502049817号