大家好,我是冰河~~
对于线程池的外围类ThreadPoolExecutor来说,有哪些重要的属性和外部类为线程池的正确运行提供重要的保障呢?
ThreadPoolExecutor类中的重要属性
在ThreadPoolExecutor类中,存在几个十分重要的属性和办法,接下来,咱们就介绍下这些重要的属性和办法。
ctl相干的属性
AtomicInteger类型的常量ctl是贯通线程池整个生命周期的重要属性,它是一个原子类对象,次要用来保留线程的数量和线程池的状态,咱们看下与这个属性相干的代码如下所示。
//次要用来保留线程数量和线程池的状态,高3位保留线程状态,低29位保留线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//线程池中线程的数量的位数(32-3)
private static final int COUNT_BITS = Integer.SIZE - 3;
//示意线程池中的最大线程数量
//将数字1的二进制值向右移29位,再减去1
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
//线程池的运行状态
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
//获取线程状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
//获取线程数量
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
private boolean compareAndDecrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect - 1);
}
private void decrementWorkerCount() {
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
对于线程池的各状态阐明如下所示。
- RUNNING:运行状态,能接管新提交的工作,并且也能解决阻塞队列中的工作
- SHUTDOWN: 敞开状态,不能再接管新提交的工作,然而能够解决阻塞队列中曾经保留的工作,当线程池处于RUNNING状态时,调用shutdown()办法会使线程池进入该状态
- STOP: 不能接管新工作,也不能解决阻塞队列中曾经保留的工作,会中断正在解决工作的线程,如果线程池处于RUNNING或SHUTDOWN状态,调用shutdownNow()办法,会使线程池进入该状态
- TIDYING: 如果所有的工作都曾经终止,无效线程数为0(阻塞队列为空,线程池中的工作线程数量为0),线程池就会进入该状态。
- TERMINATED: 处于TIDYING状态的线程池调用terminated ()办法,会应用线程池进入该状态
也能够依照ThreadPoolExecutor类的正文,将线程池的各状态之间的转化总结成如下图所示。
- RUNNING -> SHUTDOWN:显式调用shutdown()办法, 或者隐式调用了finalize()办法
- (RUNNING or SHUTDOWN) -> STOP:显式调用shutdownNow()办法
- SHUTDOWN -> TIDYING:当线程池和工作队列都为空的时候
- STOP -> TIDYING:当线程池为空的时候
- TIDYING -> TERMINATED:当 terminated() hook 办法执行实现时候
其余重要属性
除了ctl相干的属性外,ThreadPoolExecutor类中其余一些重要的属性如下所示。
//用于寄存工作的阻塞队列
private final BlockingQueue<Runnable> workQueue;
//可重入锁
private final ReentrantLock mainLock = new ReentrantLock();
//寄存线程池中线程的汇合,拜访这个汇合时,必须取得mainLock锁
private final HashSet<Worker> workers = new HashSet<Worker>();
//在锁外部阻塞期待条件实现
private final Condition termination = mainLock.newCondition();
//线程工厂,以此来创立新线程
private volatile ThreadFactory threadFactory;
//回绝策略
private volatile RejectedExecutionHandler handler;
//默认的回绝策略
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
ThreadPoolExecutor类中的重要外部类
在ThreadPoolExecutor类中存在对于线程池的执行至关重要的外部类,Worker外部类和回绝策略外部类。接下来,咱们别离看这些外部类。
Worker外部类
Worker类从源代码上来看,实现了Runnable接口,阐明其本质上是一个用来执行工作的线程,接下来,咱们看下Worker类的源代码,如下所示。
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
private static final long serialVersionUID = 6138294804551838833L;
//真正执行工作的线程
final Thread thread;
//第一个Runnable工作,如果在创立线程时指定了须要执行的第一个工作
//则第一个工作会寄存在此变量中,此变量也能够为null
//如果为null,则线程启动后,通过getTask办法到BlockingQueue队列中获取工作
Runnable firstTask;
//用于寄存此线程齐全的工作数,留神:应用了volatile关键字
volatile long completedTasks;
//Worker类惟一的结构放大,传递的firstTask能够为null
Worker(Runnable firstTask) {
//避免在调用runWorker之前被中断
setState(-1);
this.firstTask = firstTask;
//应用ThreadFactory 来创立一个新的执行工作的线程
this.thread = getThreadFactory().newThread(this);
}
//调用内部ThreadPoolExecutor类的runWorker办法执行工作
public void run() {
runWorker(this);
}
//是否获取到锁
//state=0示意锁未被获取
//state=1示意锁被获取
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() { acquire(1); }
public boolean tryLock() { return tryAcquire(1); }
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
在Worker类的构造方法中,能够看出,首先将同步状态state设置为-1,设置为-1是为了避免runWorker办法运行之前被中断。这是因为如果其余线程调用线程池的shutdownNow()办法时,如果Worker类中的state状态的值大于0,则会中断线程,如果state状态的值为-1,则不会中断线程。
Worker类实现了Runnable接口,须要重写run办法,而Worker的run办法实质上调用的是ThreadPoolExecutor类的runWorker办法,在runWorker办法中,会首先调用unlock办法,该办法会将state置为0,所以这个时候调用shutDownNow办法就会中断以后线程,而这个时候曾经进入了runWork办法,就不会在还没有执行runWorker办法的时候就中断线程。
留神:大家须要重点了解Worker类的实现。
回绝策略外部类
在线程池中,如果workQueue阻塞队列满了,并且没有闲暇的线程池,此时,持续提交工作,须要采取一种策略来解决这个工作。而线程池总共提供了四种策略,如下所示。
- 间接抛出异样,这也是默认的策略。实现类为AbortPolicy。
- 用调用者所在的线程来执行工作。实现类为CallerRunsPolicy。
- 抛弃队列中最靠前的工作并执行当前任务。实现类为DiscardOldestPolicy。
- 间接抛弃当前任务。实现类为DiscardPolicy。
在ThreadPoolExecutor类中提供了4个外部类来默认实现对应的策略,如下所示。
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());
}
}
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
咱们也能够通过实现RejectedExecutionHandler接口,并重写RejectedExecutionHandler接口的rejectedExecution办法来自定义回绝策略,在创立线程池时,调用ThreadPoolExecutor的构造方法,传入咱们本人写的回绝策略。
例如,自定义的回绝策略如下所示。
public class CustomPolicy implements RejectedExecutionHandler {
public CustomPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
System.out.println("应用调用者所在的线程来执行工作")
r.run();
}
}
}
应用自定义回绝策略创立线程池。
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
Executors.defaultThreadFactory(),
new CustomPolicy());
明天就到这儿吧,我是冰河,咱们下期见~~
发表回复