线程池
线程池的实现原理
1)线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程。
2)线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
3)线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
线程池的创建
我们可以通过ThreadPoolExecutor来创建一个线程池。
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,
milliseconds,runnableTaskQueue, handler);
1)corePoolSize(线程池的基本大小)
2)runnableTaskQueue(任务队列)
a)ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按FIFO(先进先出)原则对元素进行排序。
b)LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO排序元素,吞吐量通常要高于ArrayBlockingQueue。
c)SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于Linked-BlockingQueue
d)PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
3)maximumPoolSize(线程池最大数量)
4)ThreadFactory:用于设置创建线程的工厂
5)RejectedExecutionHandler(饱和策略): 默认情况下是AbortPolicy
a)AbortPolicy:直接抛出异常。
b)CallerRunsPolicy:只用调用者所在线程来运行任务。
c)DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
d)DiscardPolicy:不处理,丢弃掉。
6) keepAliveTime(线程活动保持时间)
7) TimeUnit(线程活动保持时间的单位)
向线程池提交任务
可以使用两个方法向线程池提交任务,分别为execute()和submit()方法。
execute()方法:用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。execute()方法输入的任务是一个Runnable类的实例。
submit()方法:用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个
future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。
关闭线程池
可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池。
shutdownNow:首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表
Shutdown:只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。
Executor框架
Executor框架的主要成员:ThreadPoolExecutor、ScheduledThreadPoolExecutor、
Future接口、Runnable接口、Callable接口和Executors。
ThreadPoolExecutor
通常使用工厂类Executors来创建。Executors可以创建3种类型的
ThreadPoolExecutor:SingleThreadExecutor、FixedThreadPool和CachedThreadPool。
FixedThreadPool
①CorePoolSize = maximumPoolSize = nThreads
②keepAliveTime=0L
③使用无界队列LinkedBlockingQueue
SingleThreadExecutor
①corePoolSize = maximumPoolSize = 1
②使用无界队列LinkedBlockingQueue
CachedThreadPool
①corePoolSize = 0
②maximumPoolSize = Integer.MAX_VALUE
③ keepAliveTime = 60L
④使用没有容量的SynchronousQueue
ScheduledThreadPoolExecutor
通常使用工厂类Executors来创建。Executors可以创建2种类型的ScheduledThreadPoolExecutor。
ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor的执行主要分为两大部分:
1)当调用ScheduledThreadPoolExecutor的scheduleAtFixedRate()方法或者scheduleWith-FixedDelay()方法时,会向ScheduledThreadPoolExecutor的DelayQueue添加一个实现了RunnableScheduledFutur接口的ScheduledFutureTask。
2)线程池中的线程从DelayQueue中获取ScheduledFutureTask,然后执行任务。
SingleThreadScheduledExecutor
DelayQueue封装了一个PriorityQueue,这个PriorityQueue会对队列中的Scheduled-
FutureTask进行排序。排序时,time小的排在前面(时间早的任务将被先执行)。如果两个ScheduledFutureTask的time相同,就比较sequenceNumber,sequenceNumber小的排在前面(也就是说,如果两个任务的执行时间相同,那么先提交的任务将被先执行)。
Future接口
Future接口和实现Future接口的FutureTask类用来表示异步计算的结果。
当我们把Runnable接口或Callable接口的实现类提交(submit)给ThreadPoolExecutor或
ScheduledThreadPoolExecutor时,ThreadPoolExecutor或ScheduledThreadPoolExecutor会向我们返回一个FutureTask对象。
(4)Runnable接口和Callable接口
Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor或Scheduled-
ThreadPoolExecutor执行。它们之间的区别是Runnable不会返回结果,而Callable可以返回结果。
除了可以自己创建实现Callable接口的对象外,还可以使用工厂类Executors来把一个
Runnable包装成一个Callable。
FutureTask三种状态
1) 未启动
2) 已启动
3) 已完成
Cancel |
get |
|
未启动 |
不执行 |
阻塞到完成 |
已启动 |
(true)中断 false(无影响) |
阻塞到完成 |
已完成 |
返回false |
立即返回 |