Question
使用线程池如何实现join
使用优先级?
理论部分
线程池的优势
避免创建,销毁线程带来的损耗 对线程进行统一的调度管理
Executors封装好的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
newFixedThreadPool()
线程数目固定大小的线程池
return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),threadFactory);
使用的是无界任务阻塞队列,任务有可能会无限堆积
newCachedThreadPool()
newScheduledThreadPool()
newSingleThreadExecutor()
ThreadPoolExecutor自定义线程池
八大参数
- corePoolSize 线程池的基本大小
- maximumPoolSize 线程池的最大线程数
- keepAliveTime 空闲线程保持存活的时间
- TimeUnit unit
- BlockingQueue workQueue
- ThreadFactory threadFactory
- RejectedExecutionHandler handler
RejectedExecutionHandler handler
当线程池中的线程达到了maximumPoolSize,而任务队列也满了的时候,新增任务时的应对策略
AbortPolicy(抛出异常
AbortPolicy 中止策略(默认策略):抛出RejectedExecutionException异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());
}
DiscardPolicy(啥也不做
DiscardPolicy抛弃策略:啥也不做
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
DiscardOldestPolicy(抛弃旧任务策略
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
自定义策略
也可自定义策略:方法为实现RejectedExecutionHandler接口,重写rejectedExecution方法
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
ystem.out.println(“球球你不要再加任务了”);
//打印日志,抛弃任务
}
核心设计的三大参数
- corePoolSize 线程池的基本大小
- maximumPoolSize 线程池中的最大线程数
- workQueue 任务队列
corePoolSize
任务提交到线程池的时候,线程池会创建线程来完成任务,即使当前存在空闲线程,直到线程数大于corePoolSize的时候
maximumPoolSize
线程池中最大的线程数
workque
ArrayBlockingQueue; LinkedBlockingQueue; SynchronousQueue; PriorityBlockingQueue
LinkedBlockingQueue 无界队列
任务可以在任务队列中无限堆积 吞吐量相比ArrayBlockingQueue要高一点
ArrayBlockingQueue 有界队列
SynchronousQueue
PriorityBlockingQueue
具备优先级的无限阻塞队列
工作流程
当任务提交给ThreadPoolExecutor 线程池中, 先检查核心线程数是否已经全部使用,如果没有则交由核心线程去执行任务, 如果核心线程数已经全部占用,则将任务添加到队列里面, 如果队列已经占满,比较当前线程池的中线程的数量是不是与超过maximumPoolSize, 如果没有查过则创建线程去执行, 也就是说线程池最多可以接受多少任务呢?就是maximumPoolSize+队列的大小。 当线程池中的线程的数量大于corePoolSize数量有空闲线程则执行回收,回收时间是keepAliveTime,单位是unit,都是初始化的时候设置的
提交任务
可以使用execute()(提交不需要返回值的任务)
可以使用submit()(提交需要返回值的任务)
execute()
submit()
线程池会返回一个future类型的对象
合理地配置线程池
CPU密集型的任务,线程数尽可能少:CPU个数+1个线程 IO密集型的任务,线程数可以多 2 * CPU个数 尽量使用有界队列
监控线程池
Example
本文使用 mdnice 排版