文章目录
JUC源码简析
线程安全性:多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。
如何保证一个类的线程安全:
-
变量不共享
变量在线程间隔离。例如:局部变量、ThreadLocal等。
-
共享不可变
-
共享可变加同步
-
乐观锁
对数据的安全性持乐观的态度,认为该数据不会被别人改变,就算改变了再选择"原谅"就好了。
代表:CAS
-
悲观锁
对数据的安全性持悲观的态度,认为共享的数据必定会被改变,所以在使用该数据时必须强占。
代表:synchronized、ReentrantLock等。
-
同步机制实现
1、保证共享变量原子性
这个可以解决单个变量类的线程安全性。
AtomicInteger等类
i++ 是复合操作,AtomicInteger#incrementAndGet()是原子操作。
2、加锁机制
a) synchronized关键字,是内置锁
b) 基于AQS实现的相关类,例如ReentrantLock,显示锁即通过代码加锁解锁
ThreadPoolExecutor代码片段
// 成员变量
private final HashSet<Worker> workers = new HashSet<Worker>();
private int largestPoolSize;// 记录线程池中最大线程数量
addWorker(Worker w)方法片段
boolean workerAdded = false;
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();
}
添加工作线程和修改最大线程数是要保证原子性的操作,必须添加同步操作保证数据的安全性。
原子类
基础类:Unsafe类
-
操纵对象属性
// 获取对象属性的偏移量,然后可以通过这个内存偏移量直接修改数据 public native long objectFieldOffset(Field var1);
-
操纵数组元素
// 获取数组第一个元素的偏移地址 public native int arrayBaseOffset(Class<?> var1); // 获取数组中元素的增量地址,配合base使用可以获取数组中任意元素的偏移地址 public native int arrayIndexScale(Class<?> var1);
-
线程挂起与恢复
public native void unpark(Object var1); public native void park(boolean var1, long var2);
-
CAS
// var1:哪个对象 var2:哪个偏移量(哪个属性) var4:预期值(原始值) var5:修改值 public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5); public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
AmoticInteger
public final int addAndGet(int delta) { // 等价于 ++i
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));// 自旋CAS
return var5;
}
CAS的两个问题:
1、ABA
如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。
2、高并发下的性能问题
自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。
AtomicStampedReference
解决了ABA问题,加了一个stamp,可以用时间戳。
private volatile Pair<V> pair;
private static class Pair<T> {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
LongAdder
jdk1.8 解决高并发下性能问题
设计思想:热点分离,有点类似HashTable(node数组) -> ConcurrentHashMap(node节点)
也有点像一台机器扛不住了,多部几台来分担压力。
![img](https://i-blog.csdnimg.cn/blog_migrate/e8eeb226ca4efd239afc52c9d40173fa.pngimg src=“https://i-blog.csdnimg.cn/blog_migrate/15aa4cccd1f5604be9bb2eb785ff076e.png” alt=“img” style=“zoom: 33%;” />
将一个原子变量拆分成base+Cell[]数组,如果base不存在竞争关系则跟AmoticInteger之前一样,如果存在竞争关系则会初始化Cell数组,然后多个线程去操作Cell数组中的某一个元素,如果操作失败则去操作另一个Cell。获取值result = base + Cell[]数组的值
代码如下
public void add(long x) {
Cell[] as; long b, v; int m; Cell a;
// casBase失败了才会去初始化Cell数组
if ((as = cells) != null || !casBase(b = base, b + x)) {
boolean uncontended = true;
if (as == null || (m = as.length - 1) < 0 ||
(a = as[getProbe() & m]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
longAccumulate(x, null, uncontended);
}
}
// 获取值 sum = base + Cell[]
public long sum() {
Cell[] as = cells; Cell a;
long sum = base;
if (as != null) {
for (int i = 0; i < as.length; ++i) {
if ((a = as[i]) != null)
sum += a.value;
}
}
return sum;
}
同步器
基础类:
AbstractQueuedSynchronizer
简称AQS,是一个同步框架(模板)。该类基于模板方法模式定义好了模板,暴露出去几个钩子方法,子类按需实现这些方法就可以做一个同步器,关键点有两个,一个是state的含义,一个是钩子方法的实现。
AQS主要有三方面内容:
1、独占模式
2、共享模式
3、条件队列
关键变量
// 同步状态
private volatile int state;
// 等待队列(同步队列)
// 头结点
private transient volatile Node head;
// 尾节点
private transient volatile Node tail;
static final class Node {
// 等待状态
volatile int waitStatus;
// 等待队列双向
volatile Node prev;
volatile Node next;
// 线程
volatile Thread thread;
// 条件队列单向
Node nextWaiter;
}
获取锁
独占模式和共享模式获取锁逻辑基本一致,共享模式比独占模式多了一步,获取到锁之后会进行传播,即唤醒后继的共享模式线程,前提条件是还有共享锁可以获取。
public final void acquire(int arg) { // 独占模式获取锁
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// 将当前线程封装成node节点添加到等待队列
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node); // 初始化队列
return node;
}
// 获取锁
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) { // 如果是头结点之后的尝试获取锁
setHead(node); // 会将node节点的线程清空,与new Node()保持一致
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) && // 判断是否需要阻塞
parkAndCheckInterrupt())// 阻塞
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
释放锁
释放锁成功,去唤醒等待队列中阻塞的线程。
public final boolean release(int arg) {
if (tryRelease(arg)) { // 尝试释放锁
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h); // 唤醒等待线程
return true;
}
return false;
}
条件队列
ConditionObject,AQS的内部类
public class ConditionObject implements Condition{
/** First node of condition queue. */
private transient Node firstWaiter;
/** Last node of condition queue. */
private transient Node lastWaiter;
}
public interface Condition {
// 阻塞
void await() throws InterruptedException;
// 唤醒条件队列第一个阻塞线程
void signal();
// 唤醒条件队列所有阻塞线程
void signalAll();
}
await() 对标 Object类中wait()
signal() 对标 Object类中notify()
signalAll() 对标 Object类中notifyAll()
这些方法都必须拿到锁之后才能调用。
await()会先释放锁,然后放在条件队列中进行阻塞。如果被唤醒之后如果当前节点在等待队列中又会去获取锁。
signal()将节点从条件队列移到等待队列中,然后唤醒该节点线程。
使用场景:生产者消费者模型
阻塞队列 BlockingQueue take put
基于AQS实现的同步器,关键就是以下两点:
- 明确state的含义。
- 实现对应的方法。主要是以下方法:
// 互斥锁
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
protected boolean isHeldExclusively() {
throw new UnsupportedOperationException();
}
// 共享锁
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
基于AQS实现的同步工具类
ReentrantLock
可重入互斥锁,与synchronized语义基本相同。
可重入:如果当前线程拥有A锁,还可以去获取A锁。
公平锁:当发生竞争时,每个线程按先后顺序依次获取锁。先来的线程必定先获取锁。
公平锁的优势和劣势?
非公平锁:线程并不是按先后顺序获取锁,可能后面的线程先获取锁。
非公平锁的优势和存在的问题?提示:公平锁的性能好还是非公平锁?为什么?线程饥饿。
内部结构如下图
内部类Sync
// 继承自AQS
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
abstract void lock();
/**
* 这个方法就能很直观看出state在ReentrantLock的语义了,不为0就表示上锁了。
*/
final boolean isLocked() {
return getState() != 0;
}
/**
* 非公平尝试获取锁,就是将state从0变到1(获取锁),或者从1变到n(可重入语义)
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();// 获取AQS中state的值
if (c == 0) {// 说明锁还是自由状态
if (compareAndSetState(0, acquires)) {// 直接通过cas获取锁,如果为true则说明获取成功
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {// 这里就表明了可重入语义
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);// 因为已经获取到锁了,所以不用通过CAS来操作
return true;
}
return false;
}
/**
* 释放锁,state从1到0或者从n到n-1的过程,只有state=0时才表示释放锁成功
*/
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {
acquire(1);
}
//
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() && // 公平锁多了这一步,尝试获取锁之前先看看等待队列中是否有等待线程
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
// 非公平锁
static final class NonfairSync extends Sync {
final void lock() {
if (compareAndSetState(0, 1)) // 非公平锁会直接去尝试获取锁
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
synchronized是非公平锁,ReentrantLock有公平锁和非公平锁选择。非公平锁性能是优于公平锁的,因为非公平锁减少了线程的频繁切换。但非公平锁可能会产生 线程饥饿 问题。就是可能等待队列中的线程长时间获取不到锁。
CountDownLatch
首先要明确state在CountDownLatch中的作用。
线程能通过await方法之前调用countDown方法的次数。这一句话就让我们对CountDownLatch这个类有一定的了解了,也知道了await方法和countDown方法的作用。这个在构造函数中有解释。
/**
* Constructs a {@code CountDownLatch} initialized with the given count.
*
* @param count the number of times {@link #countDown} must be invoked
* before threads can pass through {@link #await}
* @throws IllegalArgumentException if {@code count} is negative
*/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
然后再看看钩子函数的实现。
重写了AQS的tryAcquireShared方法和tryReleaseShared方法,说明是通过AQS的共享模式实现的。我们来看看这两个方法。
// 尝试获取锁,state=0表示获取锁成功,否则失败
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
// 尝试释放锁,将state-1,如果减一之后state=0则表示锁释放成功
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
await()
获取锁,获取不到就等待。
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
countDown()
释放锁,如果count为0表示释放成功。释放成功就去唤醒获取锁的线程,即调用await()方法的线程。
public void countDown() {
sync.releaseShared(1);
}
并发集合
CopyOnWriteArrayList
读多写少 ,用到ReentrantLock
private transient volatile Object[] array;
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
// add方法
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
ConcurrentHashMap
通过CAS + synchronized(node节点)实现
final V putVal(K key, V value, boolean onlyIfAbsent) {
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable(); // CAS初始化数组
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null))) // CAS给数组下标赋值
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
synchronized (f) { // 数组下标有node节点就上锁
if (tabAt(tab, i) == f) {
doSomething();
}
}
}
}
return null;
}
ArrayBlockingQueue
通过ReentrantLock+Condition实现
阻塞队列的take和put方法
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0) // 表示已经空了,消费者需要阻塞
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) // 表示已经满了,生产者需要阻塞
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
线程池
为什么要使用线程池?线程池的优势:
- 复用线程可以降低系统的资源消耗。-- 减少频繁创建和销毁线程的资源消耗
- 通过已有线程来处理请求,可以提高系统响应效率。-- 减少创建和销毁线程的时间
- 方便管理线程,保证系统的稳定性,防止并发量大而导致无限制创建线程产生OOM等问题。
- 提供更强大的功能,如延时定时线程池等。
主要介绍一下ThreadPoolExecutor类
ThreadPoolExecutor
结构体系
顶级接口 Executor,只有一个方法
public interface Executor {
/**
* 执行一个任务,但并不要求是同步执行还是异步执行,这取决于实现者。
* command表示一个需要执行的任务
*/
void execute(Runnable command);
}
ExecutorService扩展了Executor接口,添加了获取任务返回值的sumbit方法,关闭线程池的shutDown和shutDownNow等方法
public interface ExecutorService extends Executor {
/**
* 关闭线程池,但会把提交给线程池的任务都执行完再关闭
*/
void shutdown();
/**
* 立即关闭线程池,给正在执行的任务发中断指令,并返回队列中未执行的任务
*/
List<Runnable> shutdownNow();
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
}
AbstractExecutorService
实现了ExecuteService接口方法
public abstract class AbstractExecutorService implements ExecutorService {
/**
* 入参是Runnable,返回值为Future
* 这个方法的关键逻辑主要是newTaskFor方法和execute方法。
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask); // 还是会调用execute方法
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
/**
* 这个方法仅仅是将Runnable转换成一个RunnableFuture,具体实现在FutureTask构造方法中
*/
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
}
Future
Future接口代表了异步任务的结果。有获取任务结果的方法get(),还有取消任务的方法cancel()
public interface Future<V> {
/**
* 取消任务
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* 获取任务计算结果,阻塞直到任务完成
*/
V get() throws InterruptedException, ExecutionException;
/**
* 获取计算任务,阻塞指定的时间,如果还没有获取到则抛出TimeoutException
*/
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
submit方法实际上返回的是FutureTask对象
FutureTask
结构体系
FutureTask作为RunnableFuture一个实现类
FutureTask封装了执行线程runner和需要执行的任务callable。然后通过状态state控制任务的执行及状态变化。
主要属性
/**
* 任务的执行状态,volatile修饰,保证可见性
* 初始化的时候为NEW状态,状态可能的变化过程:
* NEW -> COMPLETING -> NORMAL -- 正常执行
* NEW -> COMPLETING -> EXCEPTIONAL -- 抛出异常
* 以上两种情况在run()方法中设置的,以下两种情况实在cancel方法中设置的
* NEW -> CANCELLED -- 取消
* NEW -> INTERRUPTING -> INTERRUPTED -- 中断
*/
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
/** 封装的callable,Runnable也封装在里面 */
private Callable<V> callable;
/** get方法的返回结果,也可能是一个Exception */
private Object outcome; // non-volatile, protected by state reads/writes
/** 执行这个callable的线程 */
private volatile Thread runner;
/** 等待者 */
private volatile WaitNode waiters;
// WaitNode仅仅是封装了当前线程的单向链表
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
构造方法
两个构造函数,一个接收Callable,一个接收Runnable.
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
// 将Runnable转换为Callable,这里使用的是适配器模式
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
// 适配器模式:实现目标接口,依赖原接口,目标接口方法调用原有接口方法,从而达到适配的目的
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
V get() 方法
该方法可以在任务执行完成之后获取任务的返回值,如果任务没有执行完则一直阻塞。
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)// 表示是初始状态或处理中状态,需要阻塞直到执行成功
s = awaitDone(false, 0L);
return report(s);
}
/**
* 等待完成 或 因中断或超时而中止
* timed:是否使用时间等待
* nanos:使用时间等待的时间,单位纳秒
*/
private int awaitDone(boolean timed, long nanos) throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;// 等待截至时间,0表示无线等待
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) { // 表示不在初始状态和处理中,直接返回
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // 如果正在执行任务,则让出cpu时间片
Thread.yield();
else if (q == null) // 表示在初始状态
q = new WaitNode();
else if (!queued) // 第二次循环仍然在初始状态
queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);// 将当前线程放在链表头部
else if (timed) { // 第三次循环仍然在初始状态,如果设置了等待时间则线程阻塞等待的时间
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q); // 删除该节点
return state;
}
LockSupport.parkNanos(this, nanos);
}
else // 第三次循环仍然在初始状态,且没有设置等待时间,则进行阻塞直到被唤醒
LockSupport.park(this);
}
}
// 这个方法很简单,正常状态返回结果,其他状态都抛异常
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
run()
从之前的submit方法源码中可以看出,execute(futureTask)将futureTask作为Runnable执行了,所以会执行这个run()方法。
run方法对真正要执行的任务进行了控制,如果不是NEW状态就不会执行任务,执行的结果或者异常放outcome属性中,然后改变state。
public void run() {
// 先将runner设置为当前线程,不是新建状态直接返回
if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) { // 处于新建状态才执行
V result;
boolean ran;
try {
result = c.call(); // 这里会去调用真正的方法
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex); // 设置异常
}
if (ran)
set(result); // 设置返回结果
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s); // 等待state变成已中断
}
}
// NEW -> COMPLETING(瞬间) -> EXCEPTIONAL(最终)
protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion(); // 唤醒所有等待的线程
}
}
// NEW -> COMPLETING(瞬间) -> NORMAL(最终)
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
cancel(boolean mayInterruptIfRunning)
取消任务。如果任务状态不为NEW,即任务已经执行完成,则直接返回false。
if mayInterruptIfRunning == true. NEW -> INTERRUPTING -> 修改线程中断标志 -> INTERRUPTED(终态)
else NEW -> CANCELLED(终态)
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW && // 如果不是NEW状态,直接返回false
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
ThreadPoolExecutor
核心是execute方法,方法执行逻辑:
- 如果当前线程池中线程数小于核心线程数corePoolSize,则创建一个新的线程处理该任务。
- 如果大于等于核心线程数,则直接把该任务加入阻塞队列中。
- 如果该任务无法加入到阻塞队列中(可能队列中已经满了)排队,则新建线程处理该任务。
- 如果新建线程失败(已经达到最大线程数maximumPoolSize),则使用拒绝策略拒绝该任务。
执行逻辑如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZF75MKqJ-1624258590484)(C:\Users\songbz2\AppData\Roaming\Typora\typora-user-images\image-20210621095822139.png)]
主要属性
// 一个int存两个数:线程池工作线程数(后29位)+线程池状态(前3位)。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 线程池的状态
private static final int RUNNING = -1 << COUNT_BITS; // 111
private static final int SHUTDOWN = 0 << COUNT_BITS; // 000
private static final int STOP = 1 << COUNT_BITS; // 001
private static final int TIDYING = 2 << COUNT_BITS; // 010
private static final int TERMINATED = 3 << COUNT_BITS; // 011
// 存放任务的阻塞队列
// 作用:缓冲、任务提交和执行进行解耦
private final BlockingQueue<Runnable> workQueue;
// 存放线程池中所有的工作线程
private final HashSet<Worker> workers = new HashSet<Worker>();
// 线程池达到的最大线程数,用来记录的,小于等于maximumPoolSize
private int largestPoolSize;
// 完成任务数量
private long completedTaskCount;
// 创建工作线程的工厂
private volatile ThreadFactory threadFactory;
// 拒绝任务处理器(提供4种处理器,也可以自己实现,默认抛异常)
private volatile RejectedExecutionHandler handler;
// 空闲线程等待工作的超时时间
private volatile long keepAliveTime;
// 如果为false(默认),则即使处于空闲状态,核心线程也保持活动状态。
// 如果为true,则核心线程使用keepAliveTime来超时等待工作
private volatile boolean allowCoreThreadTimeOut;
// 核心线程数
private volatile int corePoolSize;
// 线程池最大线程数,这个需要我们设置的
// 作用:为了增强线程池的弹性工作。
private volatile int maximumPoolSize;
// 获取线程池状态
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; }
构造方法
corePoolSize:核心线程数大小
maximumPoolSize:最大线程数大小
keepAliveTime:空闲存活时间
unit:时间单位
workQueue:存放任务的阻塞队列
threadFactory:创建工作线程的工厂
handler:拒绝策略处理器
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;
}
execute方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true)) // 将command作为第一个任务开启一个核心线程处理
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) { // 加入阻塞队列中
int recheck = ctl.get();// double-check
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)// 如果没有工作线程了新建一个
addWorker(null, false); // 只是单纯创建一个普通线程
}
else if (!addWorker(command, false)) // 将command作为第一个任务开启一个普通线程处理
reject(command);
}
worker
这个类继承了AQS,简单重写了独占模式对应的方法,实现了Runnable接口。
Worker封装了工作线程,也封装了任务,因为Worker实现了Runnable接口,则可以把自己交给线程去执行。
private final class Worker extends AbstractQueuedSynchronizer implements Runnable
{
/** 工作线程*/
final Thread thread;
/** 需要完成的初始化任务,可能为null */
Runnable firstTask;
/** 当前线程完成任务计数器 */
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1); // runWorker之前禁止中断
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this); // 创建一个新线程,该线程会执行this.run方法。
}
public void run() {
runWorker(this);
}
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) {
}
}
}
}
addWorker
添加工作线程到workers集合,并执行任务firstTask。
firstTask:第一个任务
core:是否为核心线程
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) { // 将线程数量+1
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)) // 只有这里为true才会退出外层for循环
break retry;
c = ctl.get(); // Re-read ctl
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 {
w = new Worker(firstTask); // 创建一个新线程
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
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); // 将w添加到集合中
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start(); // 添加成功后就执行任务,调用t.start方法为什么后面会执行worker.run方法呢?答案就在创建t的时候,可以回过去看看
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
runWorker(Worker w)
执行提交给线程池的任务,如果当前worker没有任务,则去队列中取任务执行。如果任务都执行完了,则处理worker退出,即线程数量减1,把当前worker工作的任务数汇总,然后从worker集合中删除。
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);// 处理worker退出
}
}
getTask()
从等待队列中获取任务,如果是核心线程那就一直等待任务直到获取成功,如果是非核心线程则等待对应时间,如果还没有获取到任务则将worker数量减1并返回null。
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();
if (r != null)
return r; // 获取到任务
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
jdk1.6之后新增的一些类:
ForkJoinPool、CompletableFuture、StampedLock等