五.线程池
线程池是为了提高由于频繁创建线程而大大降低的系统效率,如果并发的线程很多,并且每个线程都执行了一个时间很短的任务就结束了,因为频繁创建线程和销毁线程需要时间,线程池使线程可以复用,就是执行完一个任务不被销毁,继续执行其他的任务。
①.继承实现
从最核心的ThreadPoolExecutor类开始,ThreadPoolExecutor继承于AbstractExecutorService抽象类,
AbstractExecutorService抽象类实现了ExecutorService接口,ExecutorService实现了Executor接口,
Executor中定义了关键方法:
void execute(Runnable command);
ExecutorService接口中新定义了很多方法:
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
AbstractExecutorService抽象类中实现了ExecutorService接口中的submit的不同参数的三个方法,
并且新加入了一些方法
ThreadPoolExecutor类中,直接使用的父类(AbstractExecutorService)的方法,未复写submit(),但是实现了shutdown(),shutdownNow(),execute(…);
submit()方法根本上也是使用execute(…)方法去执行线程的。submit()方法会有一个Future接口类型的返回值;
public void shutdown() {}
public List<Runnable> shutdownNow(){}
public void execute(Runnable command){}
/*
*submit()方法(其一)
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
②.构造方法
ThreadPoolExecutor有四个参数不同的构造方法,其实都是用参数最多的那个构造方法去构造的;
ThreadPoolExecutor(int,int,long,TimeUnit,BlockingQueue<Runnable>);
ThreadPoolExecutor(int,int,long,TimeUnit,BlockingQueue<Runnable>,ThreadFactory);
ThreadPoolExecutor(int,int,long,TimeUnit,BlockingQueue<Runnable>,RejectedExecutionHandler);
ThreadPoolExecutor(int,int,long,TimeUnit,BlockingQueue<Runnable>
,ThreadFactory,RejectedExecutionHandler);
/*
*五个参数的构造方法
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
拿第一个举例,看到其实是调用了七个参数的构造方法,使用默认的ThreadFactory和拒绝策略。
参数含义:
参数 | 使用 | |
---|---|---|
corePoolSize | 留在池中的线程数,即使它们是空闲的,除非{@code allowCoreThreadTimeOut}设置 | 这个参数是否生效取决于allowCoreThreadTimeOut变量的值,该变量默认是false,即对于核心线程没有超时限制,所以这种情况下,corePoolSize参数是起效的。 如果allowCoreThreadTimeOut为true,那么核心线程允许超时,并且超时时间就是keepAliveTime参数和unit共同决定的值,这种情况下,如果线程池长时间空闲的话最终存活的线程会变为0,也即corePoolSize参数失效。 |
maximumPoolSize | 池中允许的最大线程数 | 线程池中最大的存活线程数。这个参数比较好理解,对于超出corePoolSize部分的线程,无论allowCoreThreadTimeOut变量的值是true还是false,都会超时,超时时间由keepAliveTime和unit两个参数算出。 |
keepAliveTime | 当线程数大于核心数时,这是多余的空闲线程在终止之前等待新任务的最大时间。 | 超时时间。 |
unit | {@code keepAliveTime}参数的时间单位 | 超时时间的单位(TimeUnit类中有7种静态属性),天,小时,分,秒,毫秒,微秒,纳秒等,与keepAliveTime参数共同决定超时时间。 |
workQueue | 用于在任务执行之前保存它们的队列。这个队列将只保存由{@code execute}方法提交的{@code Runnable}任务。 | 当调用execute方法时,如果线程池中没有空闲的可用线程,那么就会把这个Runnable对象放到该队列中。这个参数必须是一个实现BlockingQueue接口的阻塞队列,因为要保证线程安全。 有一个要注意的点是,只有调用execute方法,才会向这个队列中添加任务,submit方法提交任务时,如果没有可用的线程也不会直接扔掉,AbstractExecutorService类中对submit方法的实现,submit方法只是把传进来的Runnable对象或Callable对象包装成一个新的Runnable对象,然后调用execute方法,并将包装后的FutureTask对象作为一个Future引用返回给调用者。Future的阻塞特性实际是在FutureTask中实现的。 |
threadFactory | 执行程序创建新线程时要使用的工厂 | 线程工厂类。用于在需要的时候生成新的线程。默认实现是Executors.defaultThreadFactory(),即new 一个Thread对象,并设置线程名称,daemon等属性。 |
handler | 当执行因达到线程边界和队列容量而阻塞时要使用的处理程序 | 表示当拒绝处理任务时的策略,有以下四种取值: ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程) ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 |
③比较重要的几个方法
方法 | 参数/返回值 | |
---|---|---|
execute() | Runnable command / void | 在Executor接口中声明, ThreadPoolExecutor中实现, 是ThreadPoolExecutor的核心方法, 通过这个方法可以提交一个任务给线程池,由线程池去执行。 |
submit() | Runnable task / Future<?> Runnable task, T result / Future Callable task / Future |
在ExecutorService中声明,在AbstractExecutorService中实现,通过这个方法可以提交一个任务给线程池,但是和execute()有区别,可以通过Future类型拿到返回值。 |
shutdown() | void / void | 启动一个有序的关闭,先前提交的任务将被执行,但不接受新的任务。如果已经关闭,则调用没有额外效果。 |
shutdownNow() | void / List | 尝试停止所有正在执行的任务,停止正在等待的任务的处理,并返回正在等待执行的任务的列表。当从这个方法返回时,这些任务将从任务队列中被排干(删除)。 |
参考《https://blog.csdn.net/zhuge134/article/details/88376764》
未完待续。。