Executor 框架中有两个关键类实现了 ExecutorService 接口,ThreadPoolExecutor 和 ScheduledThreadPoolExecutor
ThreadPoolExecutor有四个构造方法,这是其中之一,其他构造方法都是在此基础上传入默认参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize: 池中所保存的核心线程数,包括空闲线程。
maximumPoolSize:池中允许创建的最大线程数。当workqueue使用无界队列LinkedBlockingQueue等时,此参数无效。
keepAliveTime:当前线程池线程总数大于核心线程数时,keepAliveTime 为多余的空闲线程等待新任务的最长时间。
unit:参数的时间单位
workQueue:任务队列,如果当前线程池达到核心线程数时,且当前所有线程都处于活动状态,则将新加入的任务放到此队列中。当任务队列满了之后,且工作线程介于核心线程数和最大线程数之间,则创建新的线程执行任务。
threadFactory:设置执行程序创建新线程时使用的工厂。
handler: 饱和策略,当队列和线程池都满了,必须采取一种策略处理提交的任务,默认直接抛出异常
newFixedThreadPool 被称为可重用固定线程的线程池,下面是其源代码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newFixedThreadPool 的 corePoolSize 和 maximumPoolSize都被设置为 nThreads,keepAliveTime被设置为 0L,意味着如果线程数超过传入的参数 nThread 时,多余的空闲线程会被立即终止。
在这里因为使用了 LinkedBlockingQueue 这个无界队列,当线程数达到 nThreads 后,新任务会在无界队列中等到,无界队列不满就不会创建新的线程,所以 maximumPoolSize 是一个无效的参数。而且永远不会拒绝任务。
newSingThreadExecutor 是使用单个 worker 线程的 Executor,源码实现如下
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newSingThreadExecutor 的 corePoolSize 和 maximumPoolSize 都被设置为 1 , 其余参数与 newFixedThreadPool一样,因此可看做线程数为1 的 newFixedThreadPool。
newCachedThreadPool 是一个根据需要创建新线程的线程池,实现源码如下
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newCachedThreadPool的 corePoolSize 被设置为0,maximunPoolSize被设置为 Integer.MAX_VALUE,说明其核心线程池为空,最大线程池没有界限。keepAliveTime被设置为 60L,意味着空闲线程等待新任务的最长时间为60秒,超过60秒就会被终止。同时使用了 SynchronousQueue 这个没有容量的阻塞队列,意味着当主线程提交任务的速率大于线程池处理任务的速率时,newCachedThreadPool 会直接创建新线程来处理新任务,降低了线程的重复利用率。
第一个参数是核心线程数大小,第二个参数是最大线程数大小,第三个参数是空闲线程最大存活时间,单位为秒。第四个参数是拒绝策略。线程池的任务队列默认大小为 1000,当提交的线程数大小超过 1000 时,则执行拒绝策略。
package multithread;
import java.util.*;
public class SimpleThreadPool extends Thread{
private int coreSize; //核心线程数
private int maxSize; //最大线程数
private int curSize;//当前线程池大小
private int queueSize; //任务队列大小
private static int taskSize = 0; //统计提交的线程数
private long keepActiveTime;
private volatile boolean destroy = false;
private static final int DEFAULT_CORE_SIZE = 5; //默认核心线程数
private static final int DEFAULT_MAX_SIZE = 10; //默认最大线程数
private static final int DEFAULT_QUEUE_SIZE = 100; //默认任务队列大小
private final ThreadGroup GROUP = new ThreadGroup("Pool_Group"); //线程组名
private final String PRE_NAME = "SimpleThreadPool-"; //线程名前缀
private static int index = 0;
private final static LinkedList<Runnable> TASK_QUEUE = new LinkedList<>();
private final static List<WorkTask> THREAD_QUEUE = new ArrayList<>();
private DiscardPolicy discardPolicy;//拒绝策略
//默认拒绝策略
private final static DiscardPolicy DEFAULT_DISCARD_POLICY = () ->{
System.out.println("Discard this task");
};
public SimpleThreadPool() {
this(DEFAULT_CORE_SIZE, DEFAULT_MAX_SIZE, 0, DEFAULT_DISCARD_POLICY);
}
public SimpleThreadPool(int coreSize, int maxSize, long keepActiveTime, DiscardPolicy discardPolicy) {
this.coreSize = coreSize;
this.maxSize = maxSize;
this.keepActiveTime = keepActiveTime * 1000L;
this.queueSize = DEFAULT_QUEUE_SIZE;
this.discardPolicy = discardPolicy;
init();
}
private void init() {
for (int i = 0; i < coreSize; i++)
createWorkTask();
this.curSize = coreSize;
this.start();
}
private void createWorkTask() {
WorkTask task = new WorkTask(GROUP, PRE_NAME + ++index);
task.start();
THREAD_QUEUE.add(task);
}
@Override
public void run() {
while (!destroy) {
System.out.printf("Pool#coreSize:%d,maxSize:%d,currentSize:%d,QueueSize:%d\n\n",
this.coreSize, this.maxSize, this.curSize, TASK_QUEUE.size());
try {
Thread.sleep(5_000L);
// thread incremeneted
if (TASK_QUEUE.size() > 0 && curSize < maxSize) {
for (int i = coreSize; i < maxSize; i++) {
createWorkTask();
}
System.out.println("The pool incremented to max.");
curSize = maxSize;
}
// thread reduce
synchronized (THREAD_QUEUE) {
if (TASK_QUEUE.isEmpty() && curSize > coreSize) {
Thread.sleep(keepActiveTime);
System.out.println("===========reduce===========");
int releaseSize = curSize - coreSize;
Iterator<WorkTask> it = THREAD_QUEUE.iterator();
while (it.hasNext()) {
if (releaseSize <= 0)
break;
WorkTask task = it.next();
task.close();
task.interrupt();
it.remove();
releaseSize--;
}
curSize = coreSize;
}
}
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public void submit(Runnable runnable) {
if (destroy)
throw new IllegalStateException("The thread pool already destroy and not allow submit task.");
synchronized (TASK_QUEUE) {
if (TASK_QUEUE.size() > queueSize)
discardPolicy.discard();
if (taskSize > coreSize) {
TASK_QUEUE.addLast(runnable);
TASK_QUEUE.notifyAll();
}
taskSize++;
}
}
public void shutdown() throws InterruptedException{
while (!TASK_QUEUE.isEmpty()) {
try {
Thread.sleep(50);
} catch (Exception e) {
e.printStackTrace();
}
}
synchronized (THREAD_QUEUE) {
int initSize = THREAD_QUEUE.size();
while (initSize > 0) {
for (WorkTask task : THREAD_QUEUE) {
if (task.taskState == TaskState.BLOCKED) {
task.interrupt();
task.close();
initSize--;
} else {
Thread.sleep(10);
}
}
}
}
System.out.println("active: " + GROUP.activeCount() + " THREAD_QUEUE size: " + THREAD_QUEUE.size());
this.destroy = true;
System.out.println("The thread pool disposed.");
}
private enum TaskState {
FREE, RUNNING, BLOCKED, DEAD
}
public static class DiscardException extends RuntimeException {
public DiscardException(String message) {
super(message);
}
}
public interface DiscardPolicy {
void discard() throws DiscardException;
}
private static class WorkTask extends Thread {
private volatile TaskState taskState = TaskState.FREE;
public WorkTask(ThreadGroup group, String name) {
super(group, name);
}
public TaskState getTaskState() {
return this.taskState;
}
@Override
public void run() {
OUTER: while (taskState != TaskState.DEAD) {
Runnable runnable;
synchronized (TASK_QUEUE) {
while (TASK_QUEUE.isEmpty()) {
try {
taskState = TaskState.BLOCKED;
TASK_QUEUE.wait();
} catch (InterruptedException e) {
System.out.println("Closed.");
break OUTER;
}
}
runnable = TASK_QUEUE.removeFirst();
}
if (runnable != null) {
this.taskState = TaskState.RUNNING;
runnable.run();
this.taskState = TaskState.FREE;
}
}
}
public void close() {
this.taskState = TaskState.DEAD;
}
}
public boolean isDestroy() {
return this.destroy;
}
public static void main(String[] args) throws InterruptedException {
SimpleThreadPool threadPool = new SimpleThreadPool();
for (int i = 0; i < 50; i++) {
threadPool.submit(() -> {
System.out.println("The runnable be serviced by " + Thread.currentThread() + " start.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("The runnable be serviced by " + Thread.currentThread() + " finished.");
});
}
Thread.sleep(5_000L);
threadPool.shutdown();
}
}