先来看一下线程池的参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
corePoolSize:表示线程池核心线程数
maximumPoolSize:线程池中最大允许的线程数
keepAliveTime+unit:额外线程(线程数大于corePoolSize,小于maximumPoolSize)最大空闲时间
workQueue:工作队列 存放未被执行的任务
handler:拒绝策略
先来看看这个ctl变量:高3位表示线程池的状态,低29位表示线程池中的线程数量,线程池初始状态为RUNNING,线程池中线程数为0
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
来看核心方法execute(): 1.线程池中线程数量<corePoolSize,创建线程来处理任务 2.线程池中线程数量=corePoolSize,把任务放入等待队列中 3.当等待队列满了,线程池中线程数量<maximumPoolSize,会创建额外的线程来处理任务 4.当线程池中线程数量=maximumPoolSize,会根据拒绝策略来拒绝任务
下面我们来看看固定线程池是如何进行线程创建,线程加入线程池,执行任务的过程
ExecutorService executorService = Executors.newFixedThreadPool(3);
此时,第一个任务来了,先吃线程数量0<3,走addWorker(command, true)
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
//是通过CAS使线程数递增1
if (compareAndIncrementWorkerCount(c))
break retry;
//给整个线程池上了独占锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
//然后加入线程池workers其实是个Hashset, Hashset线程不安全,所以需要加锁来保证线程安全
workers.add(w);
//线程加入线程池后,需要释放锁
finally {
mainLock.unlock();
}
//需要来执行任务了,是走Worker.run(),再走任务task.run()
t.start();
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
task.run();
}
//线程执行完当前任务后,会从阻塞队列里获取任务核心是getTask()方法
走 LinkedBlokingQueue的workQueue.take();
固定线程池的工作队列用的是LinkedBlokingQueue有界阻塞队列,但是它的长度是Integet.MAX_VALUE...近似无界了。那么就有可能n多任务在阻塞队列里造成内存溢出