线程池
三大方法
newSingleThreadExecutor方法
线程池三大方法指的是线程池工具类Executors的三个创建线程池的方法,而newSingleThreadExecutor是其中一个,创建一个只有一个线程的线程池
源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
通过上面的源代码我们发现这个方法调用了一个ThreadPoolExecutor方法,这个方法是创建线程池的原生方法,在阿里开发手册中建议我们都使用ThreadPoolExecutor方法,而不要去使用Executors工具类中的方法,因为工具类中的线程池可能存在安全隐患。
newFixedThreadPool方法
Executors中创建一个固定线程池大小的方法
源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newCachedThreadPool方法
Executors中创建一个一个可伸缩大小的线程池,在这个方法中调用的ThreadPoolExecutor方法关于最大线程数使用的是Integer.MAX_VALUE
,十分的不安全,故不建议使用这个方法
源码
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
七大参数
在Executors中三个创建线程池的方法其实都调用了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.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;
}
int corePoolSize
线程池的核心线程数,不管多少线程调用了线程池开启线程,即使没有核心线程数量的线程也会被一直开启int maximumPoolSize
最大线程数,即包括核心线程数在内可以开启的最大的线程数long keepAliveTime
除了核心线程数之外的线程,保持空闲的最大时间数量,如果超过这个数量,空闲线程池会被关闭TimeUnit unit
超时等待即上一个保持空闲时间数量的单位BlockingQueue<Runnable> workQueue
阻塞队列,如果超过这个阻塞队列长度的线程在等待,则会开启核心线程以外的其他线程。例如,有两个核心线程,已经在工作,而阻塞队列的长度是3,当有三个以内的线程在等待被开启时,则会处于阻塞队列当中,当有超过阻塞队列长度的线程在等待,例如有4个在等待,超过阻塞队列的长度3,超过1,则会开启核心线程以外的线程一个,如果超过两个则开启两个,直到达到最大线程数。ThreadFactory threadFactory
线程工厂,简单说是用来创建线程使用的,ThreadFactory
里面只有newThread
这个方法,Executors.defaultThreadFactory()
是Executors类中使用的默认的线程工厂。RejectedExecutionHandler handler
,拒绝策略,当已经开启了最大线程数并且阻塞队列以满时,会采取一种拒绝策略,而这四种拒绝策略JDK已经帮我们定义好了,我们去使用就可以了。defaultHandler
是Executors中使用的默认的拒绝策略AbortPolicy()
。
四种拒绝策略
RejectedExecutionHandler handler
是一个接口,而这个接口有四个实现类
AbrotPolicy
拒绝策略
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());
}
}
所有的拒绝策略都只会在已经开启最大线程数并且阻塞队列以满时执行,而我们可以在源码的注释中看见这么一句话Always throws RejectedExecutionException
.这句话的意思就是当执行拒绝策略时总是会抛出异常并且不处理这一个线程。
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();
}
}
}
CallerRunsPolicy
这句话的意思是当执行拒绝策略时,让要求开启这个线程的线程来执行这个线程,例如main线程调用,则会返回让main线程来执行这个线程。当然这样也就不会抛出异常了。
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) {
}
}
什么也不做,这就产生了丢弃任务r的效果。并且不抛出异常。
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);
}
}
}
此种策略是一种DiscardPolicy
策略的升级版,除了拥有DiscardPolicy
的特性,DiscardOldestPolicy
还会尝试去和最早的竞争。