赞
踩
线程是稀缺资源,如果线程被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,所以合理的使用线程池对线程进行统一分配、调优和监控,有巨大的好处。
JDK1.5引入了Executor线程池框架,通过把任务的提交和执行进行解耦,我们只需要定义好任务(Runnable),然后将它提交给线程池,而不用关心该任务是如何执行、被哪个线程执行以及什么时候执行。
Java线程池相关类库全部位于java.util.concurrent包下,类结构如下图:
总共有四个,分别为
//1 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) //2 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, //3 ThreadFactory threadFactory) public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) //4 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
构造函数主要是对线程池参数的初始化,关于线程池参数可以参考另外一篇文章Java线程池参数解析。其中构造函数1-3最后都是调用到了构造函数4,简单分析一下4即可。
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; }
由于corePoolSize、maximumPoolSize等线程池参数已经在博客Java线程池参数解析有过叙述,故此处不再赘述。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
ctl是线程池中一个非常重要的变量,以它的低29位表示线程池中处于RUNNING状态的线程个数,高3位表示线程池所处的状态(关于线程池的状态我们待会再讲)。
private static final int COUNT_BITS = Integer.SIZE - 3;
COUNT_BITS表示RUNNING状态下的线程数对应二进制的位数,也就是29。
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
CAPACITY用于与ctl做与运算,得到RUNNING状态下线程的个数。CAPACITY的值为
000111111111111111111111111111111
private static final int RUNNING = -1 << COUNT_BITS;
RUNNING表示线程池的运行状态,可处理新任务并执行队列中的任务,十进制表示为-536870912。二进制表示为
11100000000000000000000000000000
private static final int SHUTDOWN = 0 << COUNT_BITS;
SHOTDOWN表示线程池的关闭态,不接受新任务,但处理队列中的任务,值为0。
private static final int STOP = 1 << COUNT_BITS;
STOP表示线程池的停止态,不接受新任务,不处理队列中任务,且打断运行中任务,十进制表示为536870912。二进制表示为
00100000000000000000000000000000
private static final int TIDYING = 2 << COUNT_BITS;
TIDYING表示线程池的整理态,所有任务已经结束,workerCount = 0 ,将执行terminated()方法,值为1073741824。二进制表示为
01000000000000000000000000000000
private static final int TERMINATED = 3 << COUNT_BITS;
TERMINATED表示线程池的结束态,terminated() 方法已完成,值为1610612736。二进制表示为
01100000000000000000000000000000
不难发现,在所有的五种状态中SHUTDOWN值等于0,RUNNING值小于0,其他三种状态STOP、TIDYING、TERMINATED值均大于0。
private final HashSet<Worker> workers = new HashSet<Worker>();
workers用于存储真正运行的任务Worker(后边我们会详细讲述Worker的运行原理)。
private volatile boolean allowCoreThreadTimeOut;
allowCoreThreadTimeOut用于表示核心线程在空闲一定时间之后是否过期。
为了更好的管理线程,Java线程池总共包含五种状态。要注意的是,线程池的状态要与线程的状态区别开来,这两者之间没有什么必然的联系。具体请看下图
了解线程池的五个状态,对于理解线程池的工作原理至关重要,它是基础中的基础,所以在读线程池源码前一定要了解一下它们。
接下来,我们主要分析一下execute()方法,也就是添加一个Runnable任务之后,到底发生了什么?
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 (!addWo
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。