注意:所有文章除特别说明外,转载请注明出处.
第九章 Java中的线程池
[TOC]
Java中线程池的运行场景最多的是并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池。合理使用线程池的3个好处:
1.降低资源消耗
2.提高响应速度
3.提高线程的可管理性
9.1 线程池的实现原理
当提交一个新任务到线程池时,线程池的处理流程:
1.线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下一个流程。
2.线程池判断工作队列是否已满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3.线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
1.ThreadPoolExecutor 执行execute()方法
1.如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意:执行这一步骤需要获取全局锁)。
2.如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。
3.如果无法将任务加入 BlockingQueue(队列已满),则创建新的线程来处理任务(注意:执行这一步需要获取全局锁)。
4.如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用 RejectedExecutionHandler.rejectedExceptionExecution()方法。
提示:ThreadPoolExecutor采取上述步骤的总体设计思路,为了在执行execute()方法时尽可能避免获取全局锁。
9.2 线程池的使用
9.2.1 线程池的创建
我们可通过ThreadPoolExecutor来创建一个线程池:
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds, runnableTaskQueue, handler);
1.corePoolSize 线程池基本大小
2.runnableTaskQueue 任务队列,用于保存等待执行的任务的阻塞队列
阻塞队列:ArrayBlockingQueue | LinkedBlockingQueue | SynchronousQueue | PriorityBlockingQueue
3.ThreadFactory 用于设置创建线程工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字
4.RejectedExecutionHandler(饱和策略) 当队列和线程池都满了,说明线程池处于饱和状态,需要采用一种策略处理提交的新任务。
1. AbortPolicy 直接抛出异常
2. CallerRunsPolicy 只用调用者所在线程运行任务
3. DiscardOldestPolicy 丢弃队列里最近的一个任务,并执行当前任务
4. DiscardPolicy 不处理、不丢弃
5.maximumPoolSize 线程池最大数量,线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。
9.2.2 向线程池提交任务
我们可以使用两个方法向线程池提交任务:1.execute()方法,提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。2.submit()方法,用于提交需要返回值的任务,线程池会返回一个future类型对象…。
9.2.3 关闭线程池
我们可以通过调用线程池的shutdown或者shutdownNow方法关闭线程池。
9.2.4 合理配置线程池
9.2.5 线程池的监控
监控线程池时可以使用以下属性。
1. taskCount 线程池需要执行的任务数量
2. completedTaskCount 线程池在运行过程中已完成的任务数量,小于或等于taskCount
...