Java线程池
1 背景
在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因。比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同样符合这一思想。
2 概念
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲,则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
3 组成部分
1、线程池管理器:用于创建并管理线程池。
2、工作线程:线程池中线程。
3、任务接口:每个任务必须实现的接口,以供工作线程调度任务的执行。
4、任务队列:用于存放没有处理的任务。提供一种缓冲机制。
5、结果队列:用于存放执行后返回结果的队列。
4 Java线程池ThreadPoolExecutor
ThreadPoolExecutor的构造函数声明:
-
/**
-
* Creates a new {@code ThreadPoolExecutor} with the given initial
-
* parameters.
-
*
-
* @param corePoolSize the number of threads to keep in the pool, even
-
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
-
* @param maximumPoolSize the maximum number of threads to allow in the
-
* pool
-
* @param keepAliveTime when the number of threads is greater than
-
* the core, this is the maximum time that excess idle threads
-
* will wait for new tasks before terminating.
-
* @param unit the time unit for the {@code keepAliveTime} argument
-
* @param workQueue the queue to use for holding tasks before they are
-
* executed. This queue will hold only the {@code Runnable}
-
* tasks submitted by the {@code execute} method.
-
* @param threadFactory the factory to use when the executor
-
* creates a new thread
-
* @param handler the handler to use when execution is blocked
-
* because the thread bounds and queue capacities are reached
-
* @throws IllegalArgumentException if one of the following holds:<br>
-
* {@code corePoolSize < 0}<br>
-
* {@code keepAliveTime < 0}<br>
-
* {@code maximumPoolSize <= 0}<br>
-
* {@code maximumPoolSize < corePoolSize}
-
* @throws NullPointerException if {@code workQueue}
-
* or {@code threadFactory} or {@code handler} is null
-
*/
-
public ThreadPoolExecutor(int corePoolSize,
-
int maximumPoolSize,
-
long keepAliveTime,
-
TimeUnit unit,
-
BlockingQueue<Runnable> workQueue,
-
ThreadFactory threadFactory,
-
RejectedExecutionHandler handler)
参数说明:
corePoolSize:线程池维护线程的最少数量。
maximumPoolSize:线程池维护线程的最大数量。
keepAliveTime:线程池维护线程所允许的空闲时间。
unit:线程池维护线程所允许的空闲时间的单位。
unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:
NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。
workQueue: 线程池所使用的缓冲队列。
workQueue我常用的是:java.util.concurrent.ArrayBlockingQueue
handler: 线程池对拒绝任务的处理策略。
handler有四个选择:
ThreadPoolExecutor.AbortPolicy() 抛出java.util.concurrent.RejectedExecutionException异常
ThreadPoolExecutor.CallerRunsPolicy() 重试添加当前的任务,他会自动重复调用execute()方法
ThreadPoolExecutor.DiscardOldestPolicy() 抛弃旧的任务
ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务
1、当池子大小小于corePoolSize就新建线程,并处理请求。
2、当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去从workQueue中取任务并处理。
3、当workQueue放不下新入的任务时,新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize就用RejectedExecutionHandler来做拒绝处理。
4、另外,当池子的线程数大于corePoolSize的时候,多余的线程会等待keepAliveTime长的时间,如果无请求可处理就自行销毁
5、一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。
6、当一个任务通过execute(Runnable)方法欲添加到线程池时
如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
如果此时线程池中的数量等于corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
5 Executors中几个线程池创建方法
Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
5.1 FixedThreadPool
jdk1.8.0_65代码实现:
-
/**
-
* Creates a thread pool that reuses a fixed number of threads
-
* operating off a shared unbounded queue, using the provided
-
* ThreadFactory to create new threads when needed. 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
-
* @param threadFactory the factory to use when creating new threads
-
* @return the newly created thread pool
-
* @throws NullPointerException if threadFactory is null
-
* @throws IllegalArgumentException if {@code nThreads <= 0}
-
*/
-
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
-
return new ThreadPoolExecutor(nThreads, nThreads,
-
0L, TimeUnit.MILLISECONDS,
-
new LinkedBlockingQueue<Runnable>(),
-
threadFactory);
-
}
由Executors的newFixedThreadPool方法创建。它是一种线程数量固定的线程池,当线程处于空闲状态时,他们并不会被回收,除非线程池被关闭。当所有的线程都处于活动状态时,新的任务都会处于等待状态,直到有线程空闲出来。而且核心线程没有超时机制,而且任务队列没有长度的限制。
5.2 CachedThreadPool
jdk1.8.0_65代码实现:
-
/**
-
* 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>());
-
}
由Executors的newCachedThreadPool方法创建,不存在核心线程,只存在数量不定的非核心线程,而且其数量最大值为Integer.MAX_VALUE。当线程池中的线程都处于活动时(全满),线程池会创建新的线程来处理新的任务,否则就会利用新的线程来处理新的任务,线程池中的空闲线程都有超时机制,默认超时时长为60s,超过60s的空闲线程就会被回收。和FixedThreadPool不同的是,CachedThreadPool的任务队列其实相当于一个空的集合,这将导致任何任务都会被执行,因为在这种场景下SynchronousQueue是不能插入任务的,SynchronousQueue是一个特殊的队列,在很多情况下可以理解为一个无法储存元素的队列。从CachedThreadPool的特性看,这类线程比较适合执行大量耗时较小的任务。当整个线程池都处于闲置状态时,线程池中的线程都会因为超时而被停止回收,几乎是不占任何系统资源。
5.3 ScheduledThreadPool
jdk1.8.0_65代码实现:
-
/**
-
* Creates a thread pool that can schedule commands to run after a
-
* given delay, or to execute periodically.
-
* @param corePoolSize the number of threads to keep in the pool,
-
* even if they are idle
-
* @return a newly created scheduled thread pool
-
* @throws IllegalArgumentException if {@code corePoolSize < 0}
-
*/
-
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
-
return new ScheduledThreadPoolExecutor(corePoolSize);
-
}
由
Executors的
newScheduledThreadPool方式创建,核心线程数量是固定的,而非核心线程是没有限制的,并且当非核心线程闲置时它会被立即回收,
ScheduledThreadPool这类线程池主要用于执行定时任务和具有固定时期的重复任务。
5.4 SingleThreadExecutor
jdk1.8.0_65代码实现:
-
/**
-
* 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>()));
-
}
由Executors的newSingleThreadExecutor方法来创建。这类线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。SingleThreadExecutor的意义在于统一所有外界任务一个线程中,这使得这些任务之间不需要处理线程同步的问题。
参考链接:
http://blog.chinaunix.net/uid-20577907-id-3519578.html
http://blog.csdn.net/u013762572/article/details/52204192
阅读(1696) | 评论(0) | 转发(0) |