|
对于当前的计算机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队列中,这是一种按照超时时间排序的队列结构
适用:执行周期性任务 |
|