了解线程池之前先了解一个类:
Executors类:这是一个工厂类。里面包含了创建线程池的各种方法
- newFixedThreadPool(int nThreads)方法:创建指定线程数的线程池
new newFixedThreadPool(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),new DefaultThreadFactory(),new AbortPolicy())
实际创建的是一个 核心线程数:n,最大线程数:n。线程超时时间:0。阻塞队列:LinkedBlockingQueue,最大值为Integer.MAX_VALUE。DefaultThreadFactory:默认的创建线程的工厂。AbortPolicy:当阻塞队列已满时的拒绝策略,默认的策略为抛出异常,可以自己去实现,如改为线程sleep,但是意义不大,因为阻塞队列太大,阻塞队列还没满,就已经内存溢出了。
-
newSingleThreadExecutor()方法:创建单个线程的线程池
new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),new DefaultThreadFactory(),new AbortPolicy())
实际创建的是一个 核心线程数:1,最大线程数:1。线程超时时间:0。阻塞队列:LinkedBlockingQueue,最大值为Integer.MAX_VALUE
- newCachedThreadPool()方法:创建带缓存的线程池
new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),new DefaultThreadFactory(),new AbortPolicy())
实际创建的是一个 核心线程数:0,最大线程数:int最大值,线程超时时间:60,TimeUnit.SECONDS:表示存活时间的单位,可以转化成各种时间。阻塞队列:SynchronousQueue
线程池是什么,线程池是怎么工作的?
很多初学者,包括当初的我,都曾经被各种误导,一直以为线程池中运行的线程就是我们excute的线程。
线程池里面运行的是一定数量的线程,但是这些线程不是我们通过pool.excute(Runnable thread),提交的的线程对象(excute的入参传Runnable的对象更节省空间,而不是Thread的对象)。而是通过创建线程池时,传入的线程创建工厂(DefaultThreadFactory)创建的。而通过excute提交的只是一个普通的java对象,一个实现了Runnable的类对象。线程池中对于我们的实现类中方法的调用,只是普通的run()方法调用。实际上可以把excute的对象当成一个task,task中的内容就是run()方法中的内容。
那么线程池处理的实际任务,就是我们excute的一堆Runnable对象,调用各自的run方法的过程。
测试代码:
Thread thread = new Thread(){
@Override
public void start(){
setName("自己命名的线程");
System.out.println("start");
super.start();
}
@Override
public void run(){
for (int i = 0 ; i < 10; i++) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("over!");
}
};
thread.start();
// ExecutorService executor = Executors.newFixedThreadPool(2);
// executor.execute(thread);
ThreadGroup group = Thread.currentThread().getThreadGroup();
Thread[] threads = new Thread[group.activeCount()];
int num = group.enumerate(threads);
for (int i = 0; i < threads.length; i++) {
System.out.println(threads[i].getName());
}
如果是线程直接调用start启动,则打印了"running start",而且线程的名字指定了。
如果是线程池启动,没有调用实现的start方法,而且线程的名字并非我们指定的线程名称。
其实通过excute(Runnable),传入的是Runnable类型,就能够发现这些问题,只是初学的时候,思考的不够仔细。
ThreadPoolExecutor 源码
设计思路:
铺垫
- 线程池的初始化
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 AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));//线程安全的原子数据操作
ctl的高3位记录的是线程池的运行状态,低29位记录的是线程池中的线程数。
原理private static final int COUNT_BITS = Integer.SIZE - 3;//29 private static final int CAPACITY = (1 << COUNT_BITS) - 1;//容量 低29位存储 011111111111111111111111111111 private static final int RUNNING = -1 << COUNT_BITS; //11100000000000000000000000000000 private static final int SHUTDOWN = 0 << COUNT_BITS; //00000000000000000000000000000000 private static final int STOP = 1 << COUNT_BITS; //00100000000000000000000000000000 private static final int TIDYING = 2 << COUNT_BITS; //01000000000000000000000000000000 private static final int TERMINATED = 3 << COUNT_BITS; //01100000000000000000000000000000 private static int runStateOf(int c) { return c & ~CAPACITY; }// 取c的高3位 private static int workerCountOf(int c) { return c & CAPACITY; }// 线程池的线程数,与capacity进行与操作,取低 29位k,capacity 全是1,所以是与。 private static int ctlOf(int rs, int wc) { return rs | wc; } //合并,rs是带后面0的,wc是带前面0的,进行或运行。
- 一些属性
一些核心属性private volatile boolean allowCoreThreadTimeOut;//为true时,线程数小于核心线程数,keepAliveTime依然有效。 private volatile int corePoolSize;//核心线程数 private volatile int maximumPoolSize;//最大线程数 private final BlockingQueue<Runnable> workQueue;//任务队列,用于保存等待执行的任务的阻塞队列 private volatile long keepAliveTime;//当线程数大于核心线程数是起作用 private volatile ThreadFactory threadFactory;//线程创建工厂 private volatile RejectedExecutionHandler handler;//拒绝策略 private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();//默认拒绝策略,为抛出异常
private final ReentrantLock mainLock = new ReentrantLock();//对象锁 private final HashSet<Worker> workers = new HashSet<Worker>();//用来存储待执行的任务,任务被封装成了Worker对象 private final Condition termination = mainLock.newCondition();//Condition 的实例,用于 termination.await() 相当与线程的 wait() // termination.signalAll(); //相当与线程的 notifyAll()
新增任务流程
excute方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
* 分3步
* 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))//这里会在addWorker里面详细说明,
//主要逻辑就是,如果新增线程成功,则返回。否则重新判断线程池运行状态,将任务添加到任务队列中
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);
}
addWorker方法
/**
* 首先明白这个方法是做什么的。 这个方法是新建线程的 方法。
*/
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
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;//如果线程数大于线程池容量(固定的),或者core为true时,大于核心线程数,core为false时大于最大线程数,都不创建新线程。
if (compareAndIncrementWorkerCount(c))//并发就是在这里控制的。如果ctl等于期望值c,则 ctl+1。也就是并发的多条线程执行到此处,需要一条一条通过。每次循环只能有一条线程通过。其它的线程都需要重新进入循环,重新判断。
//简单的两种情况:一种 线程数远小于核心线程数,则返回的线程将在下一次循环时,通过。
另一种 线程数只比核心线程数 小1,则循环的线程,都将在 wc >= corePoolSize 时返回false。对于这条任务 excute的第一层判断 addWork之后返回false,表示新增线程失败。此任务需要添加到队列中。
//private boolean compareAndIncrementWorkerCount(int expect) {//利用cas算法,+1
// return ctl.compareAndSet(expect, expect + 1);
// }
break retry;
c = ctl.get(); // Re-read ctl,重新获取clt
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
final ReentrantLock mainLock = this.mainLock;
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int c = ctl.get();
int rs = runStateOf(c);
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;
}