1.再说线程池之前先了解下线程、用户级线程、内核级线程概念
2.什么是线程池
3.线程池作用:
4.什么时候使用线程池,应用场景?
5.常见线程池分类
使用DelayedWorkQueue存储任务,超时时间为0.
public ThreadPoolExecutor(int corePoolSize, //核心线程数
int maximumPoolSize, //线程池容量
long keepAliveTime, //timeout时间,非核心线程存活时间
TimeUnit unit, //时间单位
BlockingQueue 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;
}
6. 线程池的状态:
7. 源码流程分析 ThreadPoolExecutor.execute()
public void execute(Runnable command) {
if (command == null) //任务为空抛异常
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get(); //判断线程池中工作线程数量是否小于核心线程数量
if (workerCountOf(c) < corePoolSize) { //创建工作线程,并启动工作线程执行任务
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) { //如果线程池是RUNNING状态并且这个时候还来任务,那么就把任务加入阻塞队列中
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); //核心线程、最大线程数以及阻塞队列都满了,那么就是用拒绝策略来处理任务
}
8.几个常见对比:
9.线程池大小确定
10.源码分析之后的疑惑
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this); //由ThreadFactory产生线程,该线程创建成功之后调用该线程的start方法会运行Runnable的任务。
//而这里传入的参数是this,也就是Worker的实例,而Worker又实现了Runnable接口,因此会调用Worker的run方法。
}
public interface ThreadFactory {
/**
* Constructs a new {@code Thread}. Implementations may also initialize
* priority, name, daemon status, {@code ThreadGroup}, etc.
*
* @param r a runnable to be executed by new thread instance
* @return constructed thread, or {@code null} if the request to
* create a thread is rejected
*/
Thread newThread(Runnable r); //@param r a runnable to be executed by new thread instance
}
为了验证上面自己的想法,我本地写了一个验证类:
package com.sap.leo;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
//自定义ThreadFactory来创建线程
public class LeoTestThreadFactory implements ThreadFactory
{
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public LeoTestThreadFactory()
{
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
package com.sap.leo;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
//测试类
public class LeoTest
{
private volatile static ThreadFactory threadFactory;
public static void main(String[] args) throws InterruptedException {
TaskDemo task = new TaskDemo();
Worker worker = new Worker(task);
Thread t = worker.getT();
t.start();
Thread.sleep(50*1000);
}
private static class TTT implements Runnable
{
@Override
public void run()
{
System.out.println("TTT.run()...");
}
}
private static final class Worker extends AbstractQueuedSynchronizer
{
private Thread t;
private Runnable task;
public Worker(Runnable task)
{
//使用自定义的ThreadFactory来创建线程,这里传递的任务是TTT
//因此该线程启动的时候会调用TTT的run方法执行相应的任务
this.t = getThreadFactory().newThread(new TTT());
this.task = task;
}
public Thread getT() {
return t;
}
public void setT(Thread t) {
this.t = t;
}
public Runnable getTask() {
return task;
}
public void setTask(Runnable task) {
this.task = task;
}
public void run()
{
runWorker(this);
}
}
public static void runWorker(Worker worker)
{
Runnable task = worker.getTask();
task.run();
}
public static ThreadFactory getThreadFactory() {
return new LeoTestThreadFactory();
}
}
输出结果:
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
//为何要先解锁???
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//只要阻塞队列不空那么就从里面取任务
while (task != null || (task = getTask()) != null) {
//处理任务过程中需要手动加锁
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
//处理任务
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
//任务执行完销毁
task = null;
w.completedTasks++;
//任务处理完手动解锁
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
我们再看看getTask()方法private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take(); //如果限定的超神时间,那么就用poll方法获取任务,没有的话就用take方法获取任务。获取完任务会把任务宠阻塞队列里面删除
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
我们再来看看一个实现的阻塞队列:ArrayBlockingQueue(有界队列),它底层使用Object[]来存储任务的。