本文整理自Java并发编程
目录
2.1.3.maximumPoolSize(线程池最大数量)
2.1.4.RejectedExecutionHandler(饱和策略)
3.2.3ScheduledThreadPoolExecutor:
线程池的好处:
1.降低资源消耗
2.提高响应速度
3.提高线程可管理性
一、线程池实现原理
线程池执行execute的四种情况:
1.如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(需获取全局锁)
2.如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue
3.如果无法将任务加入BlockingQueue(已满),则创建新线程处理任务(需获取全局锁)
4.如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution方法
二、线程池的使用
2.1创建线程池
通过new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,milliseconds,runnableTaskQueue,handler);创建一个线程池。
参数:
2.1.1.corePoolSize(线程池基本大小)
当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建新线程,等到需要执行的任务数大于线程池基本大小就不再创建。
2.1.2.runnableTaskQueue(任务队列)
ArrayBlockingQueue:基于数组的有界阻塞队列,FIFO
LinkedBlockingQueue:基于链表的阻塞队列,FIFO
SynchronousQueue:不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态
PriorityBlockingQueue:具有优先级的无限阻塞队列
建议使用有界队列。
2.1.3.maximumPoolSize(线程池最大数量)
如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。
2.1.4.RejectedExecutionHandler(饱和策略)
当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理新提交的任务。
AbortPolicy:直接抛出异常,默认策略
CallerRunsPolicy:只用调用者所在线程来运行任务
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务
DiscardPolicy:不处理,丢弃掉
也可以实现RejectedExecutionHandler接口自定义策略
2.1.5.keepAliveTime(线程活动保持时间)
线程池的工作线程空闲后,保持存活的时间
2.1.6.TimeUnit(线程活动保持时间的单位)
可选:DAYS,HOURS,MINUTES,MILLSECONDS,MICROSECONDS,NANOSECONDS
2.2向线程池提交任务
2.2.1.execute():
用于提交不需要返回值的任务
2.2.2.submit():
用于提交需要返回值的任务,线程池会返回一个future对象。通过future对象可以判断任务是否执行成功,通过future的get方法获取返回值。
2.3.关闭线程池
2.3.1.shutdown:
将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程
2.3.2.shutdownNow:
首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表
三、Executor框架
3.1结构
Executor框架主要有3部分组成:
3.1.1.任务:
Runnable接口和Callable接口
3.1.2.任务的执行:
核心接口Executor,继承Executor的ExecutorService接口。以及两个ExecutorService的实现类ThreadPoolExecutor和ScheduledThreadPoolExecutor
3.1.3.异步计算结果:
Future接口和实现Future接口的FutureTask类
主线程创建实现Runnable或Callable接口的任务对象,Executors可以把Runnable封装成Callable
把任务对象交给ExecutorService执行
如果执行submit,ExecutorService将返回FutureTask对象
主线程可以执行FutureTask.get方法等待任务执行完成,也可以执行FutureTask.cancel取消任务执行
3.2成员
3.2.1Runnable 、Callable:
两者的实现类都可以被执行,区别:
Runnable不会返回结果
Callable可以返回结果
可以把Runnable包装成Callable
3.2.2ThreadPoolExecutor:
框架核心类,线程池的实现类。通过Executor框架的工具类Executors,可创建三种类型的ThreadPoolExecutor:
1.FixedThreadPool(可重用固定线程数的线程池)
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue. At any point, at most
* {@code nThreads} threads will be active processing tasks.
* If additional tasks are submitted when all threads are active,
* they will wait in the queue until a thread is available.
* If any thread terminates due to a failure during execution
* prior to shutdown, a new one will take its place if needed to
* execute subsequent tasks. The threads in the pool will exist
* until it is explicitly {@link ExecutorService#shutdown shutdown}.
*
* @param nThreads the number of threads in the pool
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
corePoolSize和MaximumPoolSize都设置为参数nThreads
keepAliveTime设置为0L,说明多余的空闲线程会被立即终止
任务队列使用无界队列(队列容量为Integer.MAX_VALUE),说明:
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
1)线程数到达core后,新任务将在无界队列中等待,因此线程数不会超过core
2)maximum是无效参数
3)keepAliveTime是无效参数
4)运行中的Pool不会拒绝任务
2.SingleThreadExecutor(使用单个worker线程的Executor)
/**
* Creates an Executor that uses a single worker thread operating
* off an unbounded queue. (Note however that if this single
* thread terminates due to a failure during execution prior to
* shutdown, a new one will take its place if needed to execute
* subsequent tasks.) Tasks are guaranteed to execute
* sequentially, and no more than one task will be active at any
* given time. Unlike the otherwise equivalent
* {@code newFixedThreadPool(1)} the returned executor is
* guaranteed not to be reconfigurable to use additional threads.
*
* @return the newly created single-threaded Executor
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
core和maximum都设置为1.如果线程池中无运行的线程,则创建新线程执行任务,之后的任务都加入到队列中,线程执行完任务后,会在一个无限循环中反复从队列中获取任务。
3.CachedThreadPool(根据需要创建新线程的线程池)
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available. These pools will typically improve the performance
* of programs that execute many short-lived asynchronous tasks.
* Calls to {@code execute} will reuse previously constructed
* threads if available. If no existing thread is available, a new
* thread will be created and added to the pool. Threads that have
* not been used for sixty seconds are terminated and removed from
* the cache. Thus, a pool that remains idle for long enough will
* not consume any resources. Note that pools with similar
* properties but different details (for example, timeout parameters)
* may be created using {@link ThreadPoolExecutor} constructors.
*
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
core设置为0,即corePool为空
maximum设置为Integer.MAX_VALUE,即maximumPool是无界的
keepAliveTime设置为60L,说明空闲线程等待新任务的最长时间是60秒,超过60秒空闲线程将被终止
任务队列使用没有容量的SynchronousQueue,意味着如果主线程提交任务的速度超过maximumPool中线程处理任务速度时,会不断创建新的线程。极端情况下会因为创建过多线程而耗尽CPU和内存资源
3.2.3ScheduledThreadPoolExecutor:
a.继承自ThreadPoolExecutor。主要用来在给定的延迟之后运行任务,或者定期执行任务。
1)调用ScheduledThreadPoolExecutor的scheduleAtFixedRate()方法或者scheduleWithFixedDelay()方法时,会向DelayQueue中添加一个实现了RunnableScheduleFutur接口的ScheduledFutureTask
2)线程池中的线程从DelayQueue中获取ScheduledFutureTask,然后执行任务
b.为了实现周期性执行任务,对ThreadPoolExecutor做了如下修改:
1)使用DelayQueue作为任务队列(无界)
2)获取任务方式不同
3)执行周期任务后,增加额外处理
c.ScheduledFutureTask主要包含3个成员变量
1)long型成员变量time,表示任务将要被执行的具体时间
2)long型成员变量sequenceNumber,表示任务被添加到ScheduledThreadPoolExecutor中的序号
3)long型成员变量period,表示任务执行的间隔周期
d.DelayQueue封装了一个PriorityQueue,这个会对队列中的ScheduledFutureTask进行排序
1)time小的排在前面,也就是时间早的先被执行
2)如果时间相同,sequenceNumber小的排在前面,也就是执行时间相同,先提交的任务先被执行
e.ScheduledThreadPoolExecutor中线程执行某个周期任务的4个步骤:
1)线程从DelayQueue中获取已到期的ScheduledFutureTask(DelayQueue.take())。到期指的是ScheduledFutureTask的time大于等于当前时间
2)线程执行ScheduledFutureTask
3)线程修改ScheduledFutureTask的time变量为下次将要被执行的时间
4)线程把这个修改time之后的ScheduledFutureTask放回DelayQueue中(DelayQueue.add())
3.2.4FutureTask:
FutureTask除了实现Future接口之外,还实现了Runnable接口。因此FutureTask可以交给Executor执行,也可以调用线程直接执行(FutureTask.run())。根据该方法执行的时机,FutureTask可处于3种状态:
1)未启动。run方法执行前
2)已启动。run方法执行过程种
3)已完成。run方法执行正常结束,或被取消(FutureTask.cancel(...)),或异常结束
使用:
1)交给Executor执行
2)通过ExecutorService.submit(...)返回一个FutureTask,然后执行FutureTask的get或cancel方法
3)单独使用FutureTask