java 常用线程池FixedThreadPool、SingleThreadExecutor、CachedThreadPool、ScheduledThreadPool

10.1 Executor框架

10.1.1 Executor框架的两级调度模型

HotSpot VM线程模型中,Java线程(java.lang.Thread)被一一映射本地操作系统线

程。Java线程启动时建一个本地操作系统线程;当Java线个操作系统线

也会被回收。操作系度所有线程并将它分配可用的CPU。

10.1.2 Executor框架的构与成

本文将分两部分来介ExecutorExecutor构和Executor框架包含的成员组件。

 

1.Executor框架的

Executor框架主要由3大部分成如下。·。包括被行任需要实现的接口:Runnable接口或Callable接口。

·行。包括任务执行机制的核心接口Executor,以及承自Executor

ExecutorService接口。Executor框架有两个关键类实现ExecutorService接口

ThreadPoolExecutorScheduledThreadPoolExecutor)。

·异步算的果。包括接口Future实现Future接口的FutureTask

Executor框架包含的主要的与接口如10-2所示。

下面是和接口的介。

·Executor是一个接口,它是Executor框架的基,它将任的提交与任行分离开

来。

·ThreadPoolExecutor线程池的核心实现类,用来行被提交的任

·ScheduledThreadPoolExecutor是一个实现类,可以在定的延后运行命令,或者定期

行命令。ScheduledThreadPoolExecutorTimer更灵活,功能更大。

·Future接口和实现Future接口的FutureTask,代表异步算的果。

·Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutorScheduled-

ThreadPoolExecutor行。

Executor框架的使用示意10-3所示。

10-2 Executor框架的与接口

线程首先要实现Runnable或者Callable接口的任务对象。工具Executors可以把一

Runnable象封装一个Callable象(Executors.callableRunnable task)或

Executors.callableRunnable taskObject resule))。

然后可以把Runnable象直接交ExecutorService行(ExecutorService.executeRunnable

command));或者也可以把Runnable象或Callable象提交ExecutorService行(Executor-

Service.submitRunnable task)或ExecutorService.submitCallable<T>task))。

如果ExecutorService.submit),ExecutorService将返回一个实现Future接口的

(到目前止的JDK中,返回的是FutureTask象)。由于FutureTask实现Runnable,程序也可

FutureTask,然后直接交ExecutorService行。

最后,主线程可以FutureTask.get()方法来等待任务执行完成。主线程也可以FutureTask.cancelboolean mayInterruptIfRunning)来取消此任行。

以上内容来源于《JAVA并发编程的艺术》一书

 

ThreadpoolExecutor详解

 

public ThreadPoolExecutor(int corePoolSize,//核心线程数量
                          int maximumPoolSize,//最大线程数量
                          long keepAliveTime,//超时时间,超过(maximumPoolSize-corePoolSize)线程存活的时间
                          TimeUnit unit,//存活时间单位
                          BlockingQueue<Runnable> workQueue), //存放任务的队列
                           ThreadFactory threadFactory,//创建 新线程使用的工厂
                      RejectedExecutionHandler handler) {//当任务不能执行时采用的处理方式

线程池初始化时是没有创建线程的,线程池里的线程的初始化与其他线程一样,但是在完成

任务以后,该线程不会自行销毁,而是以挂起的状态返回到线程池。直到应用程序再次向线

程池发出请求时,线程池里挂起的线程就会再度激活执行任务。这样既节省了建立线程所造

成的性能损耗,也可以让多个任务反复重用同一线程,从而在应用程序生存期内节约大量开

newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {

return new ThreadPoolExecutor(nThreads, nThreads,

0L, TimeUnit.MILLISECONDS,

new LinkedBlockingQueue<Runnable>());

}

FixedThreadPool 的核心线程数和最大线程数都是指定值,也就是说当线程池中的线程数超

过核心线程数后,任务都会被放到阻塞队列中。另外 keepAliveTime 为 0意味着多余的线程会被立即终止,也就是超出核心

线程数量以外的线程空余存活时间

而这里选用的阻塞队列是 LinkedBlockingQueue,使用的是默认容量 Integer.MAX_VALUE,

相当于没有上限

这个线程池执行任务的流程如下:

1. 线程数少于核心线程数,也就是设置的线程数时,新建线程执行任务2. 线程数等于核心线程数后,将任务加入阻塞队列

3. 由于队列容量非常大,可以一直添加

4. 执行完任务的线程反复去队列中取任务执行

用途:FixedThreadPool 用于负载比较大的服务器,为了资源的合理利用,需要限制当前线程数量

FixedThreadPool使用无界LinkedBlockingQueue为线程池的工作列(列的容量

Integer.MAX_VALUE)。使用无界列作工作列会对线程池来如下影响。1)当线程池中的线程数达到corePoolSize后,新任将在无界列中等待,因此线程池中

线程数不会超corePoolSize

2)由于1,使用无界maximumPoolSize将是一个无效参数。

3)由于12,使用无界keepAliveTime将是一个无效参数。

4)由于使用无界列,运行中的FixedThreadPool(未行方法shutdown()

shutdownNow())不会拒(不会RejectedExecutionHandler.rejectedExecution方法)。

 

newCachedThreadPool

public static ExecutorService newCachedThreadPool() {

return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

60L, TimeUnit.SECONDS,

new SynchronousQueue<Runnable>());

}

CachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空

闲线程,若无可回收,则新建线程; 并且没有核心线程,非核心线程数无上限,但是每个空闲

的时间只有 60 秒,超过后就会被回收。

它的执行流程如下:

1. 没有核心线程,直接向 SynchronousQueue 中提交任务

2. 如果有空闲线程,就去取出任务执行;如果没有空闲线程,就新建一个

3. 执行完任务的线程有 60 秒生存时间,如果在这个时间内可以接到新任务,就可以继续活

下去,否则就被回收

newSingleThreadExecutor

创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定

顺序(FIFO, LIFO, 优先级)执行

 

以下部分来源于《JAVA并发编程的艺术》一书

ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor承自ThreadPoolExecutor。它主要用来在定的延之后运

行任,或者定期行任ScheduledThreadPoolExecutor的功能与Timer似,但

ScheduledThreadPoolExecutor功能更大、更灵活。Timer对应的是个后台线程,而

ScheduledThreadPoolExecutor可以在构造函数中指定多个对应的后台线程数。

ScheduledThreadPoolExecutor行主要分两大部分。

1)当ScheduledThreadPoolExecutorscheduleAtFixedRate()方法或者scheduleWith-

FixedDelay()方法,会向ScheduledThreadPoolExecutorDelayQueue添加一个实现

RunnableScheduledFutur接口的ScheduledFutureTask

2线程池中的线程从DelayQueueScheduledFutureTask,然后行任

ScheduledThreadPoolExecutor实现周期性的行任ThreadPoolExecutor做了如下

的修改。

·使用DelayQueue务队列。

·取任的方式不同(后文会明)。

·行周期任后,增加了外的理(后文会明)。

10.3.2 ScheduledThreadPoolExecutor实现

前面我提到ScheduledThreadPoolExecutor会把待度的任ScheduledFutureTask

放到一个DelayQueue中。

ScheduledFutureTask主要包含3个成员变量,如下。

·long型成员变time,表示个任将要被行的具体时间

·long型成员变sequenceNumber,表示个任被添加到ScheduledThreadPoolExecutor

的序号。

·long型成员变period,表示任务执行的隔周期。

DelayQueue封装了一个PriorityQueuePriorityQueue对队列中的Scheduled-

FutureTask行排序。排序time小的排在前面(时间早的任将被先行)。如果两个

ScheduledFutureTasktime相同,就比sequenceNumbersequenceNumber小的排在前面(也就

,如果两个任时间相同,那么先提交的任将被先行)。

首先,看看ScheduledThreadPoolExecutor中的线行周期任程。10-9

ScheduledThreadPoolExecutor中的线1行某个周期任4个步

 

10-9 ScheduledThreadPoolExecutor的任务执行步

下面是对这4个步明。

1线1DelayQueue取已到期的ScheduledFutureTaskDelayQueue.take())。到期任

是指ScheduledFutureTasktime大于等于当前时间

2线1ScheduledFutureTask

3线1修改ScheduledFutureTasktime下次将要被行的时间

4线1个修改time之后的ScheduledFutureTask放回DelayQueue中(Delay-

Queue.add())。

接下来,看看上面的步1取任程。下面是DelayQueue.take()方法的源代码实现

public E take() throws InterruptedException {

final ReentrantLock lock = this.lock;

lock.lockInterruptibly(); // 1

try {

for (;;) {

E first = q.peek();

if (first == null) {

available.await(); // 2.1

} else {

long delay = first.getDelay(TimeUnit.NANOSECONDS);

if (delay > 0) {

long tl = available.awaitNanos(delay); // 2.2

} else {

E x = q.poll(); // 2.3.1

assert x != null;

if (q.size() != 0)

available.signalAll(); // 2.3.2

return x;

}

}

}

} finally {

lock.unlock(); // 3

}

}

10-10DelayQueue.take()行示意

所示,取任3大步

1Lock

2取周期任

·如果PriorityQueue空,当前线程到Condition中等待;否则执行下面的2.2

·如果PriorityQueue元素的time时间比当前时间大,到Condition中等待到time时间;否

则执行下面的2.3

·PriorityQueue元素(2.3.1);如果PriorityQueue空,则唤醒在Condition中等待的所有线程(2.3.2)。

3Lock

ScheduledThreadPoolExecutor在一个循行步2,直到线程从PriorityQueue取到一

个元素之后(2.3.1之后),才会退出无限循束步2)。

最后,看看ScheduledThreadPoolExecutor中的线行任的步4,把

ScheduledFutureTask放入DelayQueue中的程。下面是DelayQueue.add()的源代码实现

public boolean offer(E e) {

final ReentrantLock lock = this.lock;

lock.lock(); // 1

try {

E first = q.peek();

q.offer(e); // 2.1

if (first == null || e.compareTo(first) < 0)

available.signalAll(); // 2.2

return true;

} finally {

lock.unlock(); // 3

}

}

10-11DelayQueue.add()行示意

 

 

 

所示,添加任3大步

1Lock

2)添加任

·PriorityQueue添加任

·如果在上面2.1中添加的任PriorityQueue元素,醒在Condition中等待的所有线

程。

3Lock

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值