一、线程池原理
线程池真正的实现为 ThreadPoolExecutor
构造方法:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
参数说明:
1. corePoolSize :核心线程数,默认情况下,核心线程会一直存活。
如果将 线程池对象的allowCoreThreadTimeOut 设置为true,则核心线程也会有超时策略。超时时间由 keepAliveTime 指定
2. maximumPoolSize:最大线程数,当活动线程数到达这个数值后,新的任务将被阻塞
3. keepAliveTime:非核心线程闲置时超时时长,非核心线程闲置超过此时长,将被回收。
当allowCoreThreadTimeOut为true时,核心线程闲置超过此时长也会被回收。
4. unit:keepAliveTime的单位,常用:TimeUnit.MILLISECONDS(毫秒),TimeUnit.SECONDS(秒),TimeUnit.MINUTES(分钟)。
5.workQueue:线程池中的任务队列,通过execute提交的 Runnerable参数都会储存在此队列中。
6.threadFactory:线程工厂,为线程池提供新建线程的功能
7. handler:线程池无法执行新任务时,(比如:任务队列已满)会调用handler 的 rejectedExecution方法通知调用者。(此参数不常用,默认AbortPolicy)。
ThreadPoolExecutor执行任务时规则:
1. 如果线程池中 线程数量未达到核心线程数量(corePoolSize),则直接启动一个核心线程执行任务。
2. 如果线程池中 线程数量已达到核心线程数量(corePoolSize),则任务会被插入到任务队列(workQueue)中等待执行。
3. 如果步骤2无法插入到任务队列(任务队列已满),此时如果线程数量未达到最大线程数(maximumPoolSize),那么会立刻启动一个非核心线程执行任务。
4. 步骤3中如果线程数量已达到最大线程数(maximumPoolSize),会调用 RejectedExecutionHandler 的 rejectedExecution 方法通知调用者。
二、线程池的使用及优点
优点:
1.重用线程池中的线程,减少线程创建和销毁带来的性能开销
2. 能有效控制线程池的最大并发数,避免线程之间因相互抢占资源造成的阻塞
3. 能对线程进行简单管理,并提供定时执行 及 指定间隔循环执行等功能
四种线程池的特点及简单的使用
1.缓存线程池 CachedThreadPool
线程数量不定,当线程池中线程都处于活动状态时,会创建新线程处理新任务,
否则会利用空闲线程处理新任务。
线程池中的线程都有超时机制,超时时长为60秒。(即超过60秒未处理任务的线程会被回收)
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//以一个子线程执行打印方法
//第一次执行时新建一个子线程
//第二次及以后执行时,由于第一个线程已空闲,因此会复用第一个线程,不会新建
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(index);
}
});
}
}
CachedThreadPool实际为只有非核心线程,超时时长为60秒的ThreadPoolExecutor。
SynchronousQueue很多情况下可理解为不可存储元素的队列。
/**
* 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>());
}
2.定长线程池 FixedThreadPool
线程数量固定,线程处于空闲状态时,不会被回收,除非线程池关闭。
当所有线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);//线程池固定长度为3
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
结果:每次打印3个数字,两秒后再打印三个,两秒后再打印3个(每次的三个数字顺序不保证)
FixedThreadPool实际为只有核心线程,超时时长0秒,任务队列大小没有限制的ThreadPoolExecutor
/**
* 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>());
}
3.ScheduledThreadPool
核心线程数固定,非核心线程数没有限制。
非核心线程闲置时会被立即回收
一般用于定时执行任务,和执行具有固定周期的重复任务
(1) 定时执行任务(只执行一次)
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 1, TimeUnit.SECONDS); //只执行一次,注意和重复执行的参数个数不同
}
结果:程序运行三秒后,打印出 delay 3 seconds
(2) 定期执行任务(重复执行)
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS); //延迟1秒后每3秒执行一次
}
运行结果:运行一秒后,打印 delay 1 seconds, and excute every 3 seconds ,然后每3秒打印一次 delay 1 seconds, and excute every 3 seconds
ScheduledThreadPool实际为一个 核心线程数固定,最大线程数没有限制, 超时时长为0ms,的ThreadPoolExecutor
/**
* 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);
}
/**
* Creates a new {@code ScheduledThreadPoolExecutor} with the
* given core pool size.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
4. 单线程化的线程池 SingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务都在同一个线程中按顺序执行
优点:统一所有外界任务到一个线程中,使这些任务之间不需要处理线程同步的问题。
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
运行结果: 依次打印出 0到9 ,每2秒打印一个
单线程线程池实际为一个 核心线程数为1,最大线程数为1,超时时长为0ms,的ThreadPoolExecutor
/**
* 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>()));
}