并发编程--线程池

1. 使用线程池的好处

1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

3)提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。

2. 创建线程池

Executors 工具类提供了四种不同的线程池来帮助我们创建不同需求的线程池:

newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程

newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待

newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行

newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

3. ThreadPoolExecutor

ThreadPoolExecutor构造函数中有以下几个参数:

corePoolSize:核心线程数,即在该线程池中运行的线程池个数。
maximumPoolSize:线程池最大线程数,即线程池最多可以创建的线程个数。
keepAliveTime:非核心线程的存活时间。
unit:keepAliveTime的单位,有7种取值。TimeUnit.DAYS、TimeUnit.HOURS、TimeUnit.MINUTES、TimeUnit.SECONDS、TimeUnit.MILLISECONDS、TimeUnit.MICROSECONDS、TimeUnit.NANOSECONDS。
workQueue:任务超过核心线程数后,被放置的阻塞队列。例如LinkedBlockingQueue。
threadFactory:线程工厂,用来创建线程。
handler:饱和策略,当阻塞队列已满,并且线程数已达到最大线程数时,会对新任务采取的策略。

4. 线程池处理流程

提交任务后,线程池先判断线程数是否达到了核心线程数(corePoolSize)。

如果未达到线程数,则创建核心线程处理任务;否则,就执行下一步;

然后线程池判断缓存队列是否满了。如果没满,则将任务添加到缓存队列中;否则,执行下一步;

然后因为缓存队列满了,线程池就判断线程数是否达到了最大线程数。如果未达到,则创建非核心线程处理任务;否则,就执行饱和策略,默认会抛出RejectedExecutionException异常

 

饱和策略(RejectedExecutionHandler):

当任务队列和线程池都满了时所采取的应对策略,默认是AbordPolicy,表示无法处理新任务,并抛出RejectedExecutionException异常。此外还有3种策略:

1)CallerRunsPolicy:用调用者所在的线程处理任务。此策略提供简单的反馈机制,能够减缓新任务的提交速度。

2)DiscardPolicy:不能执行任务,并将任务删除。

3)DiscardOldestPolicy:丢弃队列最近的任务,并执行当前的任务。

5. 合理配置线程池

CPU密集:指该任务要进行大量的运算操作,没有阻塞,CPU要保持全速运行;该种任务可以少配置线程数,大概和机器的cpu核数相当,这样可以使得每个线程都在执行任务

IO密集:指该任务会要进行大量的IO操作,即大量的阻塞,由于大部分线程都阻塞,故需要多配置线程数,2*cpu核数

 

posted @ 2019-04-08 17:20  Cryptonym  阅读(139)  评论(0编辑  收藏  举报