Executors
四种线程池
- newFixedThreadPool(int var0)
固定线程数, 使用了LinkedBlockingQueue队列。
public static ExecutorService newFixedThreadPool(int var0) {
return new ThreadPoolExecutor(var0, var0, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
}
- newCachedThreadPool()
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue());
}
- newSingleThreadExecutor()
单个线程任务,队列为LinkedBlockingQueue
public static ExecutorService newSingleThreadExecutor() {
return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
}
- newScheduledThreadPool(int var0)
定时任务,队列为DelayedWorkQueue
public static ScheduledExecutorService newScheduledThreadPool(int var0) {
return new ScheduledThreadPoolExecutor(var0);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
new DelayedWorkQueue());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
//线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间。默认情况下,该参数只在线程数大于corePoolSize时才有用
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
阻塞队列
阻塞队列是一种队列,一种可以在多线程环境下使用,并且支持阻塞等待的队列。也就是说,阻塞队列和一般的队列的区别就在于:
1.多线程环境支持,多个线程可以安全的访问队列
2.支持生产和消费等待,多个线程之间互相配合,当队列为空的时候,消费线程会阻塞等待队列不为空;当队列满了的时候,生产线 程就会阻塞直到队列不满。
- LinkedBlockingDeque,双端阻塞队列
使用了一个没有边界的链表来存储数据 - ArrayBlockingQueue
使用一个有边界的数组来作为存储介质 - SynchronousQueue同步队列
将任务直接交给线程处理而不保持它们 - DelayQueue延时队列
这是一个非常有趣的阻塞队列,你同样可以参考DelayedWorkQueue的实现
非阻塞队列
取的时候不会阻塞等待
- ConcurrentLinkedQueue
在底层,非阻塞队列使用的是CAS(compare and set)来实现线程执行的非阻塞。
本身是一个基于链接节点的无界线程安全队列。原子性操作当然是线程安全的,非原子性那就不安全了 - 入队方法:
add():底层调用offer();
offer():Queue接口继承下来的方法,实现队列的入队操作,不会阻碍线程的执行,插入成功返回true;
- 出队方法:
poll():移动头结点指针,返回头结点元素,并将头结点元素出队;队列为空,则返回null;
peek():移动头结点指针,返回头结点元素,并不会将头结点元素出队;队列为空,则返回null;
底层实现ThreadPoolExecutor
Java线程池ThreadPoolExecutor使用和分析(一)
http://www.cnblogs.com/trust-freedom/p/6594270.html
Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理
https://www.cnblogs.com/trust-freedom/p/6681948.html
- 执行流程
当提交一个新任务到线程池时首先线程池判断基本线程池(corePoolSize)是否已满?没满,创建一个工作线程来执行任务。满了,则进入下个流程;其次线程池判断工作队列(workQueue)是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程;最后线程池判断整个线程池(maximumPoolSize)是否已满?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务;如果线程池中的线程数量大于 corePoolSize 时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过 keepAliveTime,线程也会被终止。
-
任务调度策略
image.png
说明:
在图1中,线程池中有N个任务。"任务1", "任务2", "任务3"这3个任务在执行,而"任务3"到"任务N"在阻塞队列中等待。正在执行的任务,在workers集合中,workers集合包含3个Worker,每一个Worker对应一个Thread线程,Thread线程每次处理一个任务。
当workers集合中处理完某一个任务之后,会从阻塞队列中取出一个任务来继续执行,如图2所示。图2表示"任务1"处理完毕之后,线程池将"任务4"从阻塞队列中取出,放到workers中进行处理。
- 完整构造方法
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
- 重要属性
// 所有工作线程
private final HashSet<Worker> workers = new HashSet<Worker>();
// 存储runnable的队列
private final BlockingQueue<Runnable> workQueue;
-
重要方法
1.execute提交任务
image.png
2.addWorker() -- 添加worker线程
image.png
3.runWorker() -- 执行任务
会调用getTask()获取runnable
image.png
4.getTask() -- 获取任务
从阻塞队列拿runnable
image.png
网友评论