欢迎关注微信公众号:xiaosen_javasharejava
在上一篇文章《spring boot使用@Async异步任务》中咱们了解了使用@Async的异步任务使用,在这篇文章中咱们将学习使用线程池来建立异步任务的线程。spring
在《阿里巴巴Java开发手册中》对线程使用有以下要求:数组
接下来就让咱们就好好了解一下线程池。微信
线程池简单介绍
在Java5中引入Executor框架。框架
ThreadPoolExecutor线程池解析
其类关系图以下:异步
下图是ThreadPoolExecutor的构造方法:ide
咱们这里看构造参数最多的也是最全的方法:学习
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.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;
}
复制代码
ThreadFactory:用于设置建立线程的工厂,能够经过线程工厂给每一个建立出来的线程作些更有意义的事情,好比设置daemon和优先级等等this
RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采起一种策略处理提交的新任务。这个策略默认状况下是AbortPolicy,表示没法处理新任务时抛出异常。如下是JDK1.5提供的四种策略。spa
Executors提供的线程池方法
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
复制代码
从上面源代码能够看出新建立的newFixedThreadPool的corePoolSize和maximumPoolSize都被设置为nThreads。
说明:
- 若是当前运行的线程数小于corePoolSize,则建立新的线程来执行任务;
- 当前运行的线程数等于corePoolSize后,将任务加入LinkedBlockingQueue;
- 线程执行完1中的任务后,会在循环中反复从LinkedBlockingQueue中获取任务来执行。
FixedThreadPool使用无界队列 LinkedBlockingQueue(队列的容量为Intger.MAX_VALUE)做为线程池的工做队列会对线程池带来以下影响:
- 当线程池中的线程数达到corePoolSize后,新任务将在无界队列中等待,所以线程池中的线程数不会超过corePoolSize;
- 使用无界队列时maximumPoolSize和keepAliveTime将是无效参数;
- 运行中的newFixedThreadPool(未执行shutdown()或shutdownNow()方法)不会拒绝任务。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
复制代码
从上面源代码能够看出新建立的SingleThreadExecutor的corePoolSize和maximumPoolSize都被设置为1.其余参数和newFixedThreadPool相同。也是用的是无界队列存放。
说明:
- 若是当前运行的线程数少于corePoolSize,则建立一个新的线程执行任务;
- 当前线程池中有一个运行的线程后,将任务加入LinkedBlockingQueue
- 线程执行完1中的任务后,会在循环中反复从LinkedBlockingQueue中获取任务来执行。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
复制代码
newCachedThreadPool的corePoolSize是0,maximumPoolSize被设置为Integer.MAX.VALUE。
说明:
- SynchronousQueue是无界的,在某次添加元素后必须等待其余线程取走后才能继续添加。
- 若是没法将请求加入队列,则建立新的线程,除非建立此线程超出maximumPoolSize,在这种状况下,任务将被拒绝。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
复制代码
咱们再看一下ScheduledThreadPoolExecutor中的源码:
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
复制代码
调用schedule方法,delay是延迟多少时间执行。
以上就是Executors提供的几种常见的线程池的解析。
ThreadPoolTaskExecutor
下面咱们来看一下spring为咱们提供的线程池ThreadPoolTaskExecutor。下图是其类关系图:
private final Object poolSizeMonitor = new Object();
private int corePoolSize = 1;
private int maxPoolSize = Integer.MAX_VALUE;
private int keepAliveSeconds = 60;
private int queueCapacity = Integer.MAX_VALUE;
private boolean allowCoreThreadTimeOut = false;
@Nullable
private TaskDecorator taskDecorator;
@Nullable
private ThreadPoolExecutor threadPoolExecutor;
复制代码
这是ThreadPoolTaskExecutor类中的属性,能够看出依然须要ThreadPoolExecutor类来支持。默认使用无界队列。
在初始化方法中调用了ThreadPoolExecutor的构造器:
@Override
protected ExecutorService initializeExecutor( ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
ThreadPoolExecutor executor;
if (this.taskDecorator != null) {
executor = new ThreadPoolExecutor(
this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
queue, threadFactory, rejectedExecutionHandler) {
@Override
public void execute(Runnable command) {
Runnable decorated = taskDecorator.decorate(command);
if (decorated != command) {
decoratedTaskMap.put(decorated, command);
}
super.execute(decorated);
}
};
}
else {
executor = new ThreadPoolExecutor(
this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
queue, threadFactory, rejectedExecutionHandler);
}
if (this.allowCoreThreadTimeOut) {
executor.allowCoreThreadTimeOut(true);
}
this.threadPoolExecutor = executor;
return executor;
}
复制代码
说明:
总结
以上简单的介绍了java自带的四种线程池和spring提供的线程池,他们各有利弊,实际项目中能够根据需求选择。
欢迎关注公众号: