• 线程池学习笔记


    初识线程池

    为什么要使用线程池?

    问题一:反复创建线程开销大

    问题二:过多线程会占用太多内存

    解决思路:

    一、用少量线程 避免内存占用过多

    二、让这部分线程都保持工作,且可以反复执行任务 避免生命周期的损耗

    线程池的好处

    • 加快响应速度
    • 合理利用CPU和内存
    • 统一管理

    线程池适用场合

    • 服务器接收到大量请求时,可以减少现场的创建和销毁次数,提高服务器性能。
    • 开发中,如果需要创建5个以上的线程,就可以使用线程池进行管理。

    线程池应用

    创建和停止线程池

    线程池构造方法的参数
    参数名 类型 含义
    corePoolSize int 核心线程数
    maxPoolSize int 最大线程数
    keepAliveTime long 保持存活时间
    workQueue BlockingQueue 任务存储队列
    threadFactory ThreadFacotry 当线程池需要新的线程的时候,会使用threadFactory来生产新的线程
    Handler RejectedExecutionHandle 由于线程池无法接受你所提交的任务的拒绝策略
    添加线程池规则:

    举个例子:

    • 线程池:核心池大小为5,最大池大小为10,队列为100.

    • 因为线程中的请求最多会创建5个,然后任务将被添加到队列中,直到达到100.当队列已满时,将创建最新的线程maxPoolSize,最多到10个线程,如果再来任务,就拒绝。

    增减线程的特点
    1. 通过设置corePoolSize和maximumPoolSIze相同,就可以创建固定大小的线程池。
    2. 线程池希望保持较少的线程数,并且只有在负载变得很大时才增加它。
    3. 通过设置maximumPoolSize为很高的值,可以允许线程池容纳任意数量的并发任务。
    4. 只有在队列填满时才创建多余corePoolSize的线程,如果使用的是无界队列,那么线程池就不会超过corePoolSIze。
    keepAliveTime
    • 如果线程池当先的线程数多于corePoolSize,那么如果多余的线程空闲时间超过keepAliveTime,它们就会被终止
    ThreadFactory
    • 默认使用Executors.defaultThreadFactory()
    • 创建出来的线程都在同一个线程组
    • 如果指定ThreadFactory,那么就可以改变线程名、线程组、优先级、是否是守护线程等。
    workQueue
    • 常见的队列类型:
      1. 直接交接:SynchronousQueue
      2. 无界队列:LinkedBlockingQueue (存储的任务数量无限)
      3. 有界队列:ArrayBlockingQueue
      4. 延迟队列:DelayedWorkQueue (根据时间先后做延迟)
    线程池应该手动创建还是自动创建
    • 手动创建更好,因为这样可以更加明确线程池的运行规则,避免资源耗尽的风险
    • 正确设置线程池方法:
      • 根据不同的业务场景,设置线程池参数;比如内存多大,给线程池取什么名字等等
    线程池里的线程数量设置多少合适
    • CPU密集型(加密、计算hash等):最佳线程数为CPU核心数的1-2倍左右。
    • 耗时IO型(读写数据库、文件、网络读写等):最佳线程数一般会大于CPU核心数很多倍
      • 线程数=CPU核心数*(1+平均等待时间/平均工作时间)
      • 更精确可以压测。
    对比各种线程池的特点
    • newFixedTreadPool 固定线程的线程池
      • 特点:用的无界队列(LinkedBlockingQueue)
      • 缺点:容易造成大量内存占用,可能导致OOM(OutOfMemoryError),因为用的是无界队列
    • CachedThredPool 可缓存线程池
      • 特点:具有自动回收多余线程的功能
      • 原理:任务直接交给线程(因为是SynchronousQueue队列),线程不够用就创建,过多则回收。
    • ScheduledThreadPool
      • 特点:支持定时及周期性任务执行的线程池
    • SingleThreadExecutor 单线程的线程池
      • 特点:只会用唯一的工作线程来执行任务
      • 原理,原理和newFixedTreadPool一样,只是线程数量被设置为1
    • workStealingPool (JDK1.8加入到)
      • 跟上面的线程区别挺大
      • 场景:有子任务时,如递归。
      • 窃取功能,空闲的线程能将别的线程中的任务取出来。
      • 任务一般是不加锁的,不保证执行顺序

    为什么newFixedTreadPool和SingleThreadExecutor的Queue用的LinkedBlockingQueue?

    • 因为线程数已经固定了,新来任务数量无法估计,只能将阻塞队列数量设为无限。

    为什么CachedThredPool的Queue用的SynchronousQueue?

    • 因为CachedThredPool这种队列不需要存储,直接交给新的线程处理就行,所以用SynchronousQueue

    为什么CachedThredPool的Queue用的SynchronousQueue?

    • 因为DelayedWorkQueue可以根据时间先后做延迟
    Parameter FiedThreadPool CachedThreadPool ScheduledThreadPool SingleThreaded
    corePoolSize constructor-arg 0 constructor-arg 1
    maxPoolSize same as corePoolSize Integer.MAX_VALUE Integer.MAX_VALUE 1
    keepAliveTime 0 seconds 60 seconds 0 seconds 0 seconds
  • 相关阅读:
    【转载】著名黑客雷蒙评价几种编程语言
    【GUI开发】Swing的一本极好的入门教材
    【数据结构】数组操作(HighArrayApp.java)
    数据另存为CSV档案(也是一种excel档案)【2】------自主选择路径
    TIniFile实现打开窗体后还原用户之前的配置的功能
    sql server内连接(inner join)、外连接(left outer join、right outer join、full outer join)、记录合并(union、union all)
    @指针、Cardinal()、Integer()、指针取值解析
    关于php编程的一些小技巧
    数据库操作,同时更新多条数据
    省份,城市,地区------三级联动菜单//要加注释
  • 原文地址:https://www.cnblogs.com/greycdoer0/p/14730786.html
Copyright © 2020-2023  润新知