什么是线程池
线程池就是装有线程的池子,把要执行的线程交给线程池来处理,通过维护一定数量的线程池来达到多个线程的复用。
线程池的好处
如果不用线程池,每个线程都要通过new Thread(xxRunnable).start()的方法来创建并运行一个线程。每次创建一个和销毁一个线程都是要消耗系统资源的。当线程数达到一定数量就会耗尽系统的CPU和内存资源,也会造成GC频繁收集和停顿。而线程复用节省了很大的一部分系统资源,当线程一段时间不再有任务时自动销毁,不会常驻内存。
线程池核心类
public ThreadPoolExecutor(int corePoolSize,//线程池的核心大小,也是最小的线程池大小
int maximumPoolSize,//最大线程池大小
long keepAliveTime,//空余线程存活时间,指的是超过corePoolSize大小的空余线程多长时间后销毁
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
线程池工作流程
- 如果线程池中的线程小于corePoolSize,创建新线程执行任务
- 如果线程池中的线程大于corePoolSize,把任务存储到工作队列workQueue中等待执行
- 如果workQueue也满了,线程数小于maximumPoolSize就创建新线程执行任务;线程数大于等于maximumPoolSize就执行拒绝策略
线程池分类
Executors是JDK提供的创建线程池的工厂类
- newFixedThreadPool
固定线程池,核心线程数和最大线程固定相等,空闲存活时间为0,工作队列是最大为Integer.MAX_VALUE大小的阻塞队列。执行任务时,如果线程都很忙,就会等到工作队列有空闲线程时再执行,队列满了就执行默认的拒绝策略。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- newCachedThreadPool
带缓冲线程池,核心线程数为0,最大线程数为Integer最大值大小,超过0个的空闲线程在60秒后销毁。SynchronousQueue这是一个直接提交的队列,每个新任务都会有线程来执行。如果线程池有可用线程则执行任务,没有就创建一个来执行。线程池中的线程数不确定。一般建议执行速度较快较小的线程,不然这个最大线程池边界过大容易造成内存溢出。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- newSingleThreadExecutor
单线程线程池,核心线程数和最大线程数均为1,空闲线程存活0毫秒。每次只执行一个线程,多余的先存储到工作队列,一个一个执行,保证了线程的顺序执行。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
- newScheduledThreadPool
调度线程池,即按一定的周期执行任务,即定时任务,对ThreadPoolExecutor进行了包装。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
拒绝策略
- AbortPolicy
直接抛出拒绝异常,这也是默认的拒绝策略。
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
- CallerRunsPolicy
如果线程池未关闭,则会在调用者线程中直接执行新任务,导致主线程提交线程性能变慢。
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
- DiscardPolicy
不处理新任务,丢弃。
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
- DiscardOldestPolicy
抛弃最老的任务执行新任务
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
提交线程
ExecutorService es = Executors.newFixedThreadPool(3);//定义一个固定大小的线程池
es.submit(xxRunnble);//提交线程,execute没有返回值,不知道线程结果
es.execute(xxRunnble);//提交线程,submit返回一个Future对象,并能在主线程中通过Future的get方法捕获线程中的异常
关闭线程池
es.shutdown();//不再接受新的任务,等执行完所有任务后关闭线程池。
es.shutdownNow();//不再接受新的任务,尝试停止所有任务后关闭线程池,返回未处理的线程list列表。