IE盒子

搜索
查看: 167|回复: 1

从线程池的角度理解JAVA并发

[复制链接]

5

主题

10

帖子

19

积分

新手上路

Rank: 1

积分
19
发表于 2023-1-17 17:43:24 | 显示全部楼层 |阅读模式
对于当前的计算机CPU来说,基本上都是多核。在多核心中多线程才能发挥出最大性能优势, 在CPU密集型(计算密集型)完全是靠CPU的核数来工作,所以为了让它的优势完全发挥出来,避免过多的线程上下文切换,比较理想方案是:线程数 = CPU核数+1,IO密集型由于大部分是IO操作比较耗时,占用线程执行时间较长,我们可以多设置一些线程池中线程的数量,这样就能让在等待IO的这段时间内,线程可以去做其它事,提高并发处理效率。那么这个线程池的数据量是不是可以随便设置呢?当然不是的,请一定要记得,线程上下文切换是有代价的。目前总结了一套公式,对于IO密集型应用:线程数 = CPU核心数/(1-阻塞系数)这个阻塞系数一般为0.8~0.9之间,也可以取0.8或者0.9。套用公式,对于双核CPU来说,它比较理想的线程数就是20,当然这都不是绝对的,需要根据实际情况以及实际业务来调整。
线程池

由于我们的线程的新建和销毁都是比较耗费资源和时间的,所以就需要考虑线程的复用。所以就需要用到线程池
优点


  • 降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度, 当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • ​​提高线程的可管理性, 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
缺点


  • 适用于生存周期较短的的任务,不适用于又长又大的任务。
  • 不能对于线程池中任务设置优先级。
  • 不能标识线程的各个状态,比如启动线程,终止线程。
  • 对于任意给定的应用程序域,只能允许一个线程池与之对应。
  • 线程池所有线程都处于多线程单元中,如果想把线程放到单线程单元中,线程池就废掉了。
线程池参数

corePoolSize

线程池中保持存活的核心线程数
maximumPoolSize

当任务添加到队列中并队列已满,就会创建线程直到达到最大线程数。线程池所能运行的最大线程数
keepAliveTime

当线程没有任务执行时空闲线程的超时时间,超过这个时间线程会被回收。直到回收到的最小线程数为corePoolSize
TimeUnit

超时时间单位
workQueue

当线程数达到核心线程数, 新创建的任务会被添加到该队列中

  • ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列
  • LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列(常用)
  • PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列
  • DelayQueue: 一个使用优先级队列实现的无界阻塞队列
  • SynchronousQueue: 一个不存储元素的阻塞队列(常用)
  • LinkedTransferQueue: 一个由链表结构组成的无界阻塞队列
  • LinkedBlockingDeque: 一个由链表结构组成的双向阻塞队列
threadFactory

创建线程的工厂
handler

拒绝策略

  • AbortPolicy: 处理程序遭到拒绝,则直接抛出运行时异常 RejectedExecutionException。(默认策略)
  • CallerRunsPolicy: 调用者所在线程来运行该任务,此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
  • DiscardPolicy: 无法执行的任务将被删除。
  • DiscardOldestPolicy: 如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重新尝试执行任务(如果再次失败,则重复此过程)。
常见线程池

newCachedThreadPool

底层:返回ThreadPoolExecutor实例,corePoolSize为0;maximumPoolSize为Integer.MAX_VALUE;keepAliveTime为60L;时间单位TimeUnit.SECONDS;workQueue为SynchronousQueue(同步队列)
通俗:当有新任务到来,则插入到SynchronousQueue中,由于SynchronousQueue是同步队列,因此会在池中寻找可用线程来执行,若有可以线程则执行,若没有可用线程则创建一个线程来执行该任务;若池中线程空闲时间超过指定时间,则该线程会被销毁。
适用:执行很多短期的异步任务
newFixedThreadPool

底层:返回ThreadPoolExecutor实例,接收参数为所设定线程数量n,corePoolSize和maximumPoolSize均为n;keepAliveTime为0L;时间单位TimeUnit.MILLISECONDS;WorkQueue为:new LinkedBlockingQueue<Runnable>() 无界阻塞队列
通俗:创建可容纳固定数量线程的池子,每个线程的存活时间是无限的,当池子满了就不再添加线程了;如果池中的所有线程均在繁忙状态,对于新任务会进入阻塞队列中(无界的阻塞队列)
适用:执行长期任务
newSingleThreadExecutor

底层:FinalizableDelegatedExecutorService包装的ThreadPoolExecutor实例,corePoolSize为1;maximumPoolSize为1;keepAliveTime为0L;时间单位TimeUnit.MILLISECONDS;workQueue为:new LinkedBlockingQueue<Runnable>() 无解阻塞队列
通俗:创建只有一个线程的线程池,当该线程正繁忙时,对于新任务会进入阻塞队列中(无界的阻塞队列)
适用:按顺序执行任务的场景
NewScheduledThreadPool

底层:创建ScheduledThreadPoolExecutor实例,该对象继承了ThreadPoolExecutor,corePoolSize为传递来的参数,maximumPoolSize为Integer.MAX_VALUE;keepAliveTime为0;时间单位TimeUnit.NANOSECONDS;workQueue为:new DelayedWorkQueue() 一个按超时时间升序排序的队列
通俗:创建一个固定大小的线程池,线程池内线程存活时间无限制,线程池可以支持定时及周期性任务执行,如果所有线程均处于繁忙状态,对于新任务会进入DelayedWorkQueue队列中,这是一种按照超时时间排序的队列结构
适用:执行周期性任务
回复

使用道具 举报

3

主题

12

帖子

24

积分

新手上路

Rank: 1

积分
24
发表于 2025-3-25 01:52:41 | 显示全部楼层
珍爱生命,果断回帖。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表