zoukankan      html  css  js  c++  java
  • 并发编程(十六):线程池概述

    目录


    学习资料

    《Java并发编程的艺术》第9章


    1.简介

    线程池好处:

    • 降低资源消耗:线程创建销毁会消耗资源
    • 提高响应速度
    • 便于管理线程

    2.线程池实现原理

    线程池要素:

    • corePool:核心线程池大小
    • maximunPool:最大线程池大小
    • BlockingQueue<Runnable>:任务(阻塞)队列,四种
      • ArrayBlockingQueue:数组实现有界阻塞队列,FIFO
      • LinkedBlockingQueue:基于链表阻塞队列,FIFO,吞吐量高于ArrayBlockingQueue
      • SynchronousQueue:不存储元素的阻塞队列,吞吐量高于LinkedBlockingQueue
      • PriorityBlockingQueue:一个具有优先级的阻塞队列
    • RejectedExecutionHandler:拒绝(饱和)策略,四种
      • AbortPolicy:抛出异常
      • CallerRunsPolicy:用当前线程运行任务
      • DiscardOldestPolicy:丢弃队列里最近一个任务,并执行当前任务
      • DiscardPolicy:不处理,丢掉

    线程执行任务时会经历4个阶段:(阻塞队列不同可能具体行为不同)

    1. 核心:当前运行的线程少于corePoolSize,新建线程并执行
    2. 阻塞:当前的线程数>=corePoolSize,将任务加入BlockingQueue
    3. 最大:无法加入BlockingQueue,创建新的线程来处理任务(需要获取全局锁)
    4. 拒绝:如果创建新线程将使当前运行的线程超出maximumPoolSize,则拒绝,调用拒绝策略

    ThreadPoolException中执行任务示意图:

    线程执行任务分两种情况:

    • 创建线程时提交的任务
    • 反复从BlockingQueue获取任务执行

    3.线程池的使用

    3.1 创建线程池

    七个参数:

    • corePoolSize:核心线程池数量,调用prstartAllCoreThreads()方法会提前启动所有线程
    • maximumPoolSize:最大线程池数量,无界队列该参数没效果
    • keepAliveTime:当前的线程数量大于corePoolSize,指定时间后超过的空闲线程销毁
    • unit:keepAliveTime的单位
    • workQueue:任务队列,4种
    • threadFactory:线程工厂
    • handler:拒绝策略,4种

    3.2 提交任务

    两个方法:

    • execute(runnable):提交不需要返回值的任务
    • submit(runnable):提交需要返回值的任务
      • 会返回一个future类型的对象
      • 可以通过future.get()来阻塞当前线程,直到返回工作线程结果
      • 可以使用超时方法get(long timeout,TimeUnit unit)

    3.3 关闭线程池

    两种方式:shutdown()shutdownNow(),原理都是 遍历+interrupt方法

    • shutdown():不会停止正在执行的线程,常用
    • shutdownNow():会尝试停止所有线程,不常用

    两个判断方法:

    • isShutDown():是否调用了上面两个方法之一
    • isTerminated():是否所有线程停止

    3.4 配置线程池

    分析任务特性:

    • 性质:CPU密集型,IO密集型还是混合型
    • 优先级:高,中,低
    • 执行时间:长,中,短
    • 依赖性:是否依赖其他资源,如数据库

    性质不同规模的线程池分开处理:

    • CPU密集型:线程数配置尽可能小,如 CPU个数+1

    • IO密集型:应配置尽可能多的线程,如 2*CPU数

    • 混合型任务:拆分为一个CPU密集型和一个IO密集型,如果执行时间相差很大,不要拆

    • 获取CPU数量:

      Runtime.getRuntime().avaliableProcessors();
      

      依赖数据库连接池的任务,等待时间越长,CPU空闲时间越长,线程数应设置越大

      建议使用有界队列,能增加系统稳定性和预警能力

    3.5 线程池监控

    系统中使用了大量线程池,可以通过线程池提供的参数进行监控,可以get以下属性:

    • taskCount:线程池需要执行的任务数量
    • completedTaskCount:已完成的任务数量
    • largestPoolSize:线程池里曾经创建过的最大线程数量
    • getPoolSize:线程池的线程数量
    • getActiveCount:获取活动的线程数

    也可以扩展线程池方法,重写以下方法:

    • beforeExecute(..):执行前
    • afterExecute(..):执行后
    • terminated(..):关闭前

    4.学习总结

    1.线程池简介

    • 是什么
    • 好处:降低资源消耗,提高响应速度,便于管理线程

    2.线程池实现原理
    线程池组成:

    • corePool:核心池
    • maximumPool:最大池
    • BlockingQueue:阻塞队列 (四种)
      • ArrayBlockingQueue, LinkedBlockingQueue
      • SynchronousQueue(不存储元素)
      • PriorityBlockingQueue(优先级)
    • 饱和拒绝策略:(四种)
      抛出异常,当前线程执行,丢弃前一个,直接丢弃

    线程池执行四个阶段:
    核心池—>阻塞—>最大池—>拒绝

    3.线程池的使用

    1. 创建线程池:七个参数
      两个大小(核心池,最大池),两个时间(空闲时间,单位),工厂,阻塞队列,拒绝
    2. 提交任务:
      • execute():无返回值
      • submit():返回future
    3. 关闭线程池
      • shutdown():正常终止,执行完队列中的任务
      • shutdownNow():立即终止
      • isShutDown():是否调用了上方法
      • isTerminated():是否所有线程停止
    4. 配置线程池
      • 分析任务特性:IO密集,CPU密集, 混合型
      • 性质不同分配不同数量线程:
        • CPU密集型:少,cpu数+1
        • IO密集型:多,2倍cpu数
      • 获取CPU数:
        Runtime.getRuntime().avaliableProcessors();
      • 建议使用有界队列
    5. 线程池监控
      • 监控参数:
        • taskCount:线程池需要执行的任务数量
        • completedTaskCount:已完成的任务数量
        • largestPoolSize:线程池里曾经创建过的最大线程数量
        • getPoolSize:线程池的线程数量
        • getActiveCount:获取活动的线程数
      • 扩展:
        • beforeExecute(..):执行前
        • afterExecute(..):执行后
        • terminated(..):关闭前
  • 相关阅读:
    MySQL自定义函数 1418报错
    MySQL存储过程查询
    MySQL存储过程---游标
    MySQL存储过程---流程控制(循环)
    MySQL存储过程---流程控制(分支)
    设计模式——单例模式
    准备写一个 四川票务网的 检测票自动买汽车票功能,结果登录不上悲伤,继续研究
    python批量下载微信好友头像,微信头像批量下载
    arduino 522样本中文注释
    zabbix服务的部署
  • 原文地址:https://www.cnblogs.com/kenshine/p/14520644.html
Copyright © 2011-2022 走看看