本文的源码是jdk1.8基础上分析
Runnable和Callable区别
/**
* @author Arthur van Hoff
* @since JDK1.0
*/
package java.lang;
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
/**
* @since 1.5
* @author Doug Lea
* @param <V> the result type of method {@code call}
*/
package java.util.concurrent;
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
从源码中可以看出Runnable和Callable有如下区别
- 所在的package不同,Runnable是在java.lang下,Callable是在java.util.concurrent下
- 所属jdk版本不同,Runnable从jdk1.0就有,Callable从jdk1.5才有
- 作者不同
- Runnable不支持范型,Callable支持范型
- Runnable没有返回值,Callable有返回值
- Runnable不能抛出异常,Callable可以抛出异常
ThreadPoolExecutor有4个构造方法创建线程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
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;
}
涉及到的参数有7个
(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
每个参数解释如下
- int corePoolSize 核心线程数,包含空闲线程数
- int maximumPoolSize 最大线程数
- long keepAliveTime 线程数大于corePoolSize时,空闲线程等待新任务的最长时间
- TimeUnit unit keepAliveTime的时间单位
- BlockingQueue<Runnable> workQueue 线程数量超过核心线程数时,新来的任务需要在队列中排队
- ThreadFactory threadFactory 创建新线程时触发的factory
- RejectedExecutionHandler handler 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序
线程池的工作顺序 corePoolSize -> 任务队列 -> maximumPoolSize -> 拒绝策略
线程池处理机制如下:
- 当线程池中线程数量小于corePoolSize,每来一个新任务,则创建一个新线程
- 当线程池中线程数量等于corePoolSize,每来一个新任务,需要在workQueue中排队,当线程池中有空余线程会去workQueue取一个任务
- 当workQueue中的任务数量无法容纳时,会创建新的线程,直到线程数量达到maximumPoolSize
- 当线程池中的线程数量等于maximumPoolSize,会启用RejectedExecutionHandler进入拒绝处理
注意事项:
- corePoolSize和maximumPoolSize设置不当会影响效率,甚至耗尽线程;
- CPU密集型的任务,corePoolSize设置为cpu的核心数量-1
- IO密集型的任务,corePoolSize设置为cpu的核心数量*1.5-3
- workQueue设置不当容易导致OOM
- handler设置不当会导致提交任务时抛出异常
Executors中有12个创建线程池的方法
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
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);
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1, threadFactory));
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
其中涉及到的线程池有:
-
ThreadPoolExecutor
-
ForkJoinPool(jdk1.7新增的)
-
ScheduledThreadPoolExecutor
-
newFixedThreadPool和newSingleThreadExecutor中使用的队列是LinkedBlockingQueue,LinkedBlockingQueue的最大容量为Integer.MAX_VALUE,实际使用时可能会造成OOM
-
newCachedThreadPool中使用的队列是SynchronousQueue 3.newFixedThreadPool可以指定线程池中核心线程的大小,设置太大,容易OOM,设置太小,队列长度不断增长,会产生异常。可以使用invokeAll
try {
executor.invokeAll(tasks, 480, TimeUnit.SECONDS); //如果8分钟还未执行完,则超时重新再来,原因是如果时间过长,后面很多用户可能已经退出等待
}catch (Exception e) {
}
BlockingQueue接口实现,共有5个队列实现
- ArrayBlockingQueue
- LinkedBlockingQueue
- SynchronousQueue
- PriorityBlockingQueue
- DelayQueue
RejectedExecutionHandler接口实现,共有4个拒绝策略实现
- AbortPolicy 直接抛出异常RejectedExecutionException,默认的策略
- CallerRunsPolicy 直接由提交任务者执行这个任务
- DiscardOldestPolicy 丢弃执行队列中最老的任务,尝试为当前提交的任务腾出位置
- DiscardPolicy 直接忽略