这里分析一下concurrent包下的部分类!!!目录:
1.Unsafe
2.LockSupport
3.FutureTask
4.Executor/ExecutorService
5.AbstractExecutorService
6.ThreadPoolExecutor
7.LinkedBlockingQueue
8.AbstractQueuedSynchronizer
9.CountDownLatch
10.Semaphore
11.ReentrantLock
12.ReentrantReadWriteLock
13.AtomicInteger
concurrent包下面用到了Unsafe的CAS功能、线程挂起和恢复等等功能。当然他不止这些功能,Unsafe还可以直接操纵内存。Unsafe虽然不属于concurrent包,但concurrent.locks包下面的核心类都使用到了sun.simc.Unsafe这个类,所以放到一起,下面给出其源码分析。
类申明和构造器,单例且限制用户获取实例,一般需要用反射获取。源码如下:
public final class Unsafe
{
//单例
private static final Unsafe theUnsafe;
private static native void registerNatives();
//获取Unsafe实例
@CallerSensitive
public static Unsafe getUnsafe()
{
Class localClass = Reflection.getCallerClass();
//非Bootstrap加载器会直接抛出异常,所以可以用反射拿到Unsafe实例
if (!VM.isSystemDomainLoader(localClass.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe;
}
}
内存操作,一系列native方法,可以直接分配、重新分配、释放指定的内存,直接修改和获取指定内存保存的值,
//分配内存指定大小的内存
public native long allocateMemory(long bytes);
//根据给定的内存地址address设置重新分配指定大小的内存
public native long reallocateMemory(long address, long bytes);
//用于释放allocateMemory和reallocateMemory申请的内存
public native void freeMemory(long address);
//将指定对象的给定offset偏移量内存块中的所有字节设置为固定值
public native void setMemory(Object o, long offset, long bytes, byte value);
//设置给定内存地址的值
public native void putAddress(long address, long x);
//获取指定内存地址的值
public native long getAddress(long address);
//设置给定内存地址的long值
public native void putLong(long address, long x);
//获取指定内存地址的long值
public native long getLong(long address);
//设置或获取指定内存的byte值
public native byte getByte(long address);
public native void putByte(long address, byte x);
//其他基本数据类型(long,char,float,double,short等)的操作与putByte及getByte相同
//操作系统的内存页大小
public native int pageSize();
对象操作,获取指定对象的属性的偏移量,可以根据对象和偏移量修改属性,源码如下:
//获取字段f在实例对象中的偏移量
public native long objectFieldOffset(Field f);
//静态属性的偏移量,用于在对应的Class对象中读写静态属性
public native long staticFieldOffset(Field f);
//返回值就是f.getDeclaringClass()
public native Object staticFieldBase(Field f);
//获得给定对象偏移量上的int值,所谓的偏移量可以简单理解为指针指向该变量的内存地址,
//通过偏移量便可得到该对象的变量,进行各种操作
public native int getInt(Object o, long offset);
//设置给定对象上偏移量的int值
public native void putInt(Object o, long offset, int x);
//获得给定对象偏移量上的引用类型的值
public native Object getObject(Object o, long offset);
//设置给定对象偏移量上的引用类型的值
public native void putObject(Object o, long offset, Object x);
//其他基本数据类型(long,char,byte,float,double)的操作与getInthe及putInt相同
//设置给定对象的int值,使用volatile语义,即设置后立马更新到内存对其他线程可见
public native void putIntVolatile(Object o, long offset, int x);
//获得给定对象的指定偏移量offset的int值,使用volatile语义,总能获取到最新的int值。
public native int getIntVolatile(Object o, long offset);
//其他基本数据类型(long,char,byte,float,double)的操作与putIntVolatile及getIntVolatile相同,引用类型putObjectVolatile也一样。
//与putIntVolatile一样,但要求被操作字段必须有volatile修饰
public native void putOrderedInt(Object o,long offset,int x);
创建对象,不同于反射和构造器的创建对象的方式,源码如下:
//创建实例对象,不会调用构造方法
public native Object allocateInstance(Class cls) throws InstantiationException;
操作数组,两个方法结合可以定位数组中任意元素的地址,另一方面java规定数组长度最大为Integer.MaxValue,使用Unsafe分配内存可以实现超大数组,源码如下:
//获取第一个元素偏移地址
public native int arrayBaseOffset(Class> paramClass);
//获取元素的增量地址
public native int arrayIndexScale(Class> paramClass);
CAS操作,原子性的,cpu可以直接读取相关指令,后续concurent包下并发类封装的所有CAS操作都基于这三个方法。赋新值时,期望值与旧值相对比可以知道操作期间是否被别人修改。源码如下:
//参数1:Object为给定对象,
//参数2:offset为对象内存的偏移量,用于直接定位字段
//参数3:expected为期望值
//参数4:新值
public final native boolean compareAndSwapObject(Object paramObject1, long paramLong, Object paramObject2, Object paramObject3);
public final native boolean compareAndSwapInt(Object paramObject, long paramLong, int paramInt1, int paramInt2);
public final native boolean compareAndSwapLong(Object paramObject, long paramLong1, long paramLong2, long paramLong3);
CAS操作,封装基础方法给出的getAndAddXXX()方法,乐观方式的失败重试机制。例如AtomicInteger.getAndIncrement()就是调用这类方法实现自增。源码如下:
//1.8新增,给定对象o,根据获取内存偏移量指向的字段,将其增加delta,
//这是一个CAS操作过程,直到设置成功方能退出循环,返回旧值
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
//获取内存中最新值
v = getIntVolatile(o, offset);
//通过CAS操作
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}
//1.8新增,方法作用同上,只不过这里操作的long类型数据
public final long getAndAddLong(Object o, long offset, long delta) {
long v;
do {
v = getLongVolatile(o, offset);
} while (!compareAndSwapLong(o, offset, v, v + delta));
return v;
}
//1.8新增,给定对象o,根据获取内存偏移量对于字段,将其 设置为新值newValue,
//这是一个CAS操作过程,直到设置成功方能退出循环,返回旧值
public final int getAndSetInt(Object o, long offset, int newValue) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, newValue));
return v;
}
// 1.8新增,同上,操作的是long类型
public final long getAndSetLong(Object o, long offset, long newValue) {
long v;
do {
v = getLongVolatile(o, offset);
} while (!compareAndSwapLong(o, offset, v, newValue));
return v;
}
//1.8新增,同上,操作的是引用类型数据
public final Object getAndSetObject(Object o, long offset, Object newValue) {
Object v;
do {
v = getObjectVolatile(o, offset);
} while (!compareAndSwapObject(o, offset, v, newValue));
return v;
}
线程状态操作,注意park()挂起、unpark()恢复,是一种基于许可的方式。park()会用掉许可,unpark()可以设置许可,调用顺序无要求,但许可只有一个不能叠加。也就是说在之前调用了unpark()设置许可的情况下,后调用park()不会造成线程挂起。源码如下:
//线程调用该方法,线程将一直阻塞直到超时,或者是中断条件出现。
public native void park(boolean isAbsolute, long time);
//终止挂起的线程,恢复正常.java.util.concurrent包中挂起操作都是在LockSupport类实现的,其底层正是使用这两个方法,
public native void unpark(Object thread);
线程屏障,java的内存模型是线程+线程工作内存+主内存,在三者之间一共有4对原子操作用于变量值在三者之间的传递,具体的想要实现变量可见就要保证变量每次获取值都不从工作内存获取而是从主内存获取,这一点是volite的原理。Unsafe提供的线程屏障实现了read(从主内存读入工作内存)、write(从工作内存保存到主内存)的屏障,具体应用我没还找到,源码如下:
/*
read(读取):作用于主内存变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。
assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作。
write(写入):作用于主内存的变量,它把store操作从工作内存中一个变量的值传送到主内存的变量中。
*/
//在该方法之前的所有read操作,一定在load屏障之前执行完成
public native void loadFence();
//在该方法之前的所有write操作,一定在store屏障之前执行完成
public native void storeFence();
//在该方法之前的所有read、write操作,一定在full屏障之前执行完成,这个内存屏障相当于上面两个的合体功能
public native void fullFence();
其他操作,不常用,源码如下:
//获取持有锁,已不建议使用
@Deprecated
public native void monitorEnter(Object var1);
//释放锁,已不建议使用
@Deprecated
public native void monitorExit(Object var1);
//尝试获取锁,已不建议使用
@Deprecated
public native boolean tryMonitorEnter(Object var1);
//获取本机内存的页数,这个值永远都是2的幂次方
public native int pageSize();
//告诉虚拟机定义了一个没有安全检查的类,默认情况下这个类加载器和保护域来着调用者类
public native Class defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain);
//加载一个匿名类
public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches);
//判断是否需要加载一个类
public native boolean shouldBeInitialized(Class> c);
//确保类一定被加载
public native void ensureClassInitialized(Class> c)
先简单分析一下java下面的锁、同步机制:
自旋等待与阻塞等待:
阻塞,线程竞争资源失败,进入block等待别人唤醒,依赖于操作系统(Linxu下pthread_mutex_lock函数),阻塞的唤醒会造成内核态与用户态切换影响锁性能
自旋,线程竞争资源失败,其他线程可能会很快释放资源,当前线程循环尝试获取锁操作,避免了系统阻塞操作以提高性能,一般是循环执行空代码占着cpu不放
复合,线程竞争资源失败,先自旋等待,达到一段时间后仍然失败则进入阻塞
可重入性:
可重入,线程可以重复获取同一把锁,可以重复获取被锁的资源,或者说外层函数锁一次而内层函数再锁一次却不会造成死锁,作用就是避免死锁
偏向锁,现在几乎所有锁都可重入,在一段时间内无资源竞争情况下,线程获取锁之后在后续的获取锁操作不会触发同步或一些CAS操作
可中断性:
线程获取资源失败进入等待状态,等待时突然不想等待而直接返回资源获取失败这一结果
公平性:
公平,先请求资源的优先获取资源
非公平,对资源的获取没有时间上面的先后顺序
并发策略:
悲观,认为一定存在资源竞争即拿到的都是别人修改过的,读写资源独占
乐观,认为可能不存在资源竞争即拿到就行不管别人有没有修改过,仅在写时资源独占
无锁:
即比较替换(CAS),当前线程检测当前值是否符合预期值,如果是说明期间未被修改,则替换操作。底层由sun.simc.Unsafe类提供支持,类方法可以直接操作底层资源对指定内存地址的值进行获取、覆盖等,而CAS是使用他的变量原子操作的相关方法实现的。
synchronized同步方案:
synchronized是一种互斥,可重入,不可中断,非公平的隐式锁实现。synchronized 的底层是一个基于CAS操作的等待队列,jvm还提供了偏向锁、轻量级锁、自旋锁、锁消除的同步优化。锁释放由方法退出、异常抛出来自动释放。
Lock同步方案:
扩展AQS一系列子类实现显示的锁,利用CLH队列控制多线程并发。包括ReentrantLock、ReentrantReadWriteLock等。AQS中线程等待包括自旋等待和park阻塞等待,后者是LockSupport调用Unsafe的park()将线程丢给系统进行阻塞,全程未使用synchronized块,也扩展了Condition实现基于条件的资源并发控制。AQS同步方案如图(这里仅是独占方式,共享方式等具体源码分析见后续):
可以看到concurrent包下面的挂起与唤醒机制是使用LockSupport实现的,而LockSupport又是基于Unsafe实现的。下面分析其源码。
LockSupport源码还是比较简单的,仅仅是park()和unpark()两个方法,源码如下:
public class LockSupport {
//构造器
private LockSupport() {}
//unsafe实例
private static final sun.misc.Unsafe UNSAFE;
//下面是Thread的字段偏移量,以及静态块将其初始化
//parkBlocker字段
private static final long parkBlockerOffset;
//threadLocalRandomSeed字段
private static final long SEED;
//threadLocalRandomProbe字段
private static final long PROBE;
//threadLocalRandomProbe字段
private static final long SECONDARY;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class> tk = Thread.class;
parkBlockerOffset = UNSAFE.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
SEED = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSeed"));
PROBE = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomProbe"));
SECONDARY = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSecondarySeed"));
} catch (Exception ex) { throw new Error(ex); }
}
//thread的blocker字段就是为这里涉及的,用来记录每次挂起是因为谁(即是被谁挂起的,可以理解为挂起原因,用于分析dump文件)
//设置线程t的字段parkBlocker为arg
private static void setBlocker(Thread t, Object arg) {
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
//获取线程t的字段parkBlocker值
public static Object getBlocker(Thread t) {
if (t == null)
throw new NullPointerException();
return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
}
//恢复
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
//挂起
public static void park() {
UNSAFE.park(false, 0L);
}
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
//挂起指定时间
public static void parkNanos(Object blocker, long nanos) {
if (nanos > 0) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, nanos);
setBlocker(t, null);
}
}
public static void parkNanos(long nanos) {
if (nanos > 0)
UNSAFE.park(false, nanos);
}
//挂起到指定时间
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
setBlocker(t, null);
}
public static void parkUntil(long deadline) {
UNSAFE.park(true, deadline);
}
static final int nextSecondarySeed() {
int r;
Thread t = Thread.currentThread();
if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) {
r ^= r << 13; // xorshift
r ^= r >>> 17;
r ^= r << 5;
}
else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
r = 1; // avoid zero
UNSAFE.putInt(t, SECONDARY, r);
return r;
}
}
首先简单看一下任务相关的接口和实现类。
Future接口:用来实现异步任务获取任务结果。Callable任务返回Future对象。源码如下:
public interface Future {
//尝试取消任务
boolean cancel(boolean mayInterruptIfRunning);
//如果任务正常完成前被取消,则返回true
boolean isCancelled();
//如果任务完成,则返回true
boolean isDone();
//查询结果(一直阻塞到任务返回结果)
V get() throws InterruptedException, ExecutionException;
//查询结果(一直阻塞到指定时间)
V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;
}
Runnable接口:用来创建任务。源码如下:
public interface Runnable {
//任务执行体
public abstract void run();
}
RunnableFuture接口:Future和Runnable的子接口。任务的创建、异步支持。源码如下:
public interface RunnableFuture extends Runnable, Future {
//任务执行体
void run();
}
FutureTask类:RunnableFuture的接口实现类。是一个支持取消的异步任务执行器,支持Callable或者Runnable类型任务的执行。他方便的讲任务的执行、结果的获取放到了一起,可以阻塞式地获取任务执行结果,如果结果还未返回可以在内部维护的单链表上阻塞。
类申明,构造器,相关成员如下。使用state来记录任务的各种状态,调用CAS读写state以指挥任务的执行和和取消,指挥执行任务的线程的中断,指挥其他线程在链表上阻塞等待结果的返回。构造器可以直接用callable创建,也可以用runnable和result创建。源码如下:
public class FutureTask implements RunnableFuture {
//正常完成:NEW -> COMPLETING -> NORMAL
//抛出异常:NEW -> COMPLETING -> EXCEPTIONAL
//任务取消:NEW -> CANCELLED
//任务中断:NEW -> INTERRUPTING -> INTERRUPTED
private static final int NEW = 0;//初始状态
private static final int COMPLETING = 1;//任务完成
private static final int NORMAL = 2;//任务完成,结果被set
private static final int EXCEPTIONAL = 3;//任务完成,抛出异常
private static final int CANCELLED = 4;//任务取消
private static final int INTERRUPTING = 5;//线程设置中断标记,但是并未响应中断
private static final int INTERRUPTED = 6;//线程响应中断
//state的变换以表达任务执行的状态
private volatile int state;
//跑任务的线程
private volatile Thread runner;
//任务
private Callable callable;
//get返回的执行结果或者异常对象
private Object outcome;
//维护一个链表,线程调用get()获取结果会在链表中阻塞等待结果
private volatile WaitNode waiters;
//链表结构,jdk1.7以前是AQS构建的
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
//CAS支持
private static final sun.misc.Unsafe UNSAFE;
private static final long stateOffset;
private static final long runnerOffset;
private static final long waitersOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class> k = FutureTask.class;
stateOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("state"));
runnerOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("runner"));
waitersOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("waiters"));
} catch (Exception e) {
throw new Error(e);
}
}
//构造器
public FutureTask(Callable callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
public FutureTask(Runnable runnable, V result) {
//这里通过线程池工具类创建
this.callable = Executors.callable(runnable, result);
this.state = NEW;
}
任务的执行,run()中直接调用callable的call()任务方法,而执行者runner是当前线程,执行完毕设置结果或者异常对象然后调用finishCompletion()唤醒链表上等待结果的线程。注意最后对cancel(true)的处理是调用handlePossibleCancellationInterrupt()来响应由于取消任务使得执行线程runner的中断标记。源码如下:
//run
public void run() {
//如果状态不是new状态,那么尝试设置runner为当前线程,让当前线程跑任务
if (state != NEW ||! UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread()))
//设置失败直接退出
return;
//到这里只能是runner为当前线程,或者state不是new状态
try {
Callable 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;
//有可能调用cancel(true)中断执行,这里记录一下中断前的状态值
int s = state;
if (s >= INTERRUPTING)
//确保cancel(true)产生的中断发生在run或runAndReset方法过程中。
handlePossibleCancellationInterrupt(s);
}
}
//响应中断
private void handlePossibleCancellationInterrupt(int s) {
//如果当前正在中断过程中,自旋等待一下,等中断完成。
if (s == INTERRUPTING)
while (state == INTERRUPTING)
Thread.yield();
}
//设置运行结果
protected void set(V v) {
//正常完成:NEW -> COMPLETING -> NORMAL
//在state修改为COMPLETING成功之后设置结果
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL);
//收尾工作
finishCompletion();
}
}
//设置异常
protected void setException(Throwable t) {
//抛出异常:NEW -> COMPLETING -> EXCEPTIONAL
//在state修改为COMPLETING成功之后设置异常对象
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL);
//收尾
finishCompletion();
}
}
//收尾工作
private void finishCompletion() {
//唤醒所有在get()上阻塞的线程
for (WaitNode q; (q = waiters) != null;) {
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
//唤醒
LockSupport.unpark(t);
}
//继续向下,这里用next保存下一个要遍历的节点
WaitNode next = q.next;
if (next == null)
break;
//将当前节点next域置空以断开引用,方便每个waiters的GC
q.next = null;
q = next;
}
break;
}
}
//用于扩展
done();
//任务执行完毕,任务清空
callable = null;
}
//用于扩展,子类可以实现以实现某些回调
protected void done() { }
//执行周期性任务
//与run()差别在于,这里执行完毕后不设置结果,且返回一个布尔值表示是否执行成功
protected boolean runAndReset() {
if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
try {
Callable c = callable;
if (c != null && s == NEW) {
try {
//执行任务,只记录成功,不设置结果
c.call();
ran = true;
} catch (Throwable ex) {
setException(ex);
}
}
} finally {
runner = null;
s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
return ran && s == NEW;
}
获取结果,其他线程调用get()获取结果,如果结果还未被设置,那么awaitDone创建新节点绑定该线程并加入到链表上使用park()挂起。当然也包括removeWaiter()移除队列上指定节点的逻辑。源码如下:
//获取结果
public V get() throws InterruptedException, ExecutionException {
int s = state;
//还没完成
if (s <= COMPLETING)
//添加到链表中等待,这里不指定超时时间
s = awaitDone(false, 0L);
//真正获取结果
return report(s);
}
//获取结果,指定超时时间多了个时间过期的异常抛出
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
//添加到链表中等待,指定超时时间
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
return report(s);
}
//添加到链表中等待
private int awaitDone(boolean timed, long nanos) throws InterruptedException {
//先算出到期时间
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
//自旋
for (;;) {
//当前线程被标记中断,则移除等待节点q,抛出中段异常
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
//任务已经完成,且q不为空,返回state
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
//任务完成,还没设置结果,则让出cpu
else if (s == COMPLETING)
Thread.yield();
//创建一个节点q
else if (q == null)
q = new WaitNode();
//节点q入队,注意q绑定的是当前线程
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,q.next = waiters, q);
//未超时
else if (timed) {
//计算剩余时间
nanos = deadline - System.nanoTime();
//剩余时间没有了,则移除q,并返回
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
//还有剩余时间,则让q绑定的线程(也就是当前线程)阻塞这么长的时间
LockSupport.parkNanos(this, nanos);
}
//已经超时
else
//挂起q绑定的线程(也就是当前线程)
LockSupport.park(this);
}
}
//移除等待节点
private void removeWaiter(WaitNode node) {
if (node != null) {
//断开绑定的线程的引用
node.thread = null;
//中途发生竞争则重试
retry:
//自旋
for (;;) {
//断开q,后面的接上
for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
s = q.next;
if (q.thread != null)
pred = q;
else if (pred != null) {
pred.next = s;
if (pred.thread == null)
continue retry;
}
else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,q, s))
continue retry;
}
break;
}
}
}
//真正获取结果
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);
}
任务取消。修改state为INTERRUPTING或者CANCELLED,修改失败直接返回false,修改成功则调用finishCompletion()唤醒链表上的等待线程。源码如下:
//取消任务
public boolean cancel(boolean mayInterruptIfRunning) {
//mayInterruptIfRunning记录是否在取消时中断
//mayInterruptIfRunning为true,修改state为INTERRUPTING,失败直接返回false
//mayInterruptIfRunning为false,修改state为CANCELLED,失败直接返回false
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
//线程先标记中断,再修改state为INTERRUPTED
try {
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
//同样收尾,唤醒链表上get()阻塞的线程
finishCompletion();
}
return true;
}
public boolean isCancelled() {
return state >= CANCELLED;
}
public boolean isDone() {
return state != NEW;
}
线程资源比较重要,为了复用已经创建的线程,减少在创建和销毁线程时产生的性能开销。因为创建和管理线程非常心累,并且操作系统通常对线程数有限制,所以建议使用线程池来并发执行任务,而不是每次请求进来时创建一个线程。
Executor:将任务本身和任务的执行分离(Thread而是将全部柔和到一起很不方面管理)。用于调度Runnable和Callable。
ExecutorService :对Excetor进行扩展,提供了Future异步支持(任务提交后在需要时检查 Future是否有结果,其get() 方法是阻塞式的,如果调用时任务还没有完成,会等待直到任务执行结束)。
接口源码如下:
//顶层接口
public interface Executor {
//执行任务
void execute(Runnable command);
}
//线程池接口
public interface ExecutorService extends Executor {
//关闭线程池,不再接受新任务,等待所有任务完成
void shutdown();
//关闭线程池,不再接受新任务,返回等待执行的任务列表
List shutdownNow();
//线程池是否关闭
boolean isShutdown();
//线程池关闭,所有任务均完成则返回true
boolean isTerminated();
//阻塞,直到所有线程执行完毕或者超时
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
//提交一个任务,交给线程池执行(callable自带返回结果)
Future submit(Callable task);
//提交一个任务,交给线程池执行(runnable不自带返回结果,用result表示)
Future submit(Runnable task, T result);
//提交一个任务交给线程池执行,并返回该任务的future
Future> submit(Runnable task);
//执行给定任务集合(可指定超时时间),全部完成(未抛出异常),返回future集合
List> invokeAll(Collection extends Callable> tasks) throws InterruptedException;
List> invokeAll(Collection extends Callable> tasks, long timeout, TimeUnit unit) throws InterruptedException;
//执行给定任务(可指定超时时间),完成(未抛出异常),返回future
T invokeAny(Collection extends Callable> tasks) throws InterruptedException, ExecutionException;
T invokeAny(Collection extends Callable> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
AbstractExecutorService给出ExecutorService的一个抽象实现。用于异步任务、任务执行的调度管理等。依次分析相关方法。
创建任务,使用任务来构造FutureTask并返回,源码如下:
//创建任务
protected RunnableFuture newTaskFor(Runnable runnable, T value) {
//构造器中value用来保存任务返回结果
return new FutureTask(runnable, value);
}
protected RunnableFuture newTaskFor(Callable callable) {
return new FutureTask(callable);
}
提交任务,就是调用execute(),传入任务进行执行,这里交给子类实现。源码如下:
//提交任务
public Future> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task, null);
//抽象类没有实现execute(),这里交给子类实现
execute(ftask);
return ftask;
}
public Future submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public Future submit(Callable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
执行给定任务集合,返回一个已经成功完成的任务的结果(任务得到结果、没有抛出异常视为执行成功)。源码如下:
//执行任务集合,返回第一个执行成功的结果
private T doInvokeAny(Collection extends Callable> tasks,boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks == null)
throw new NullPointerException();
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
//构造futures集合
ArrayList> futures = new ArrayList>(ntasks);
//ExecutorCompletionService可以使用阻塞队列来保存多个线程的执行结果(future类型)
ExecutorCompletionService ecs = new ExecutorCompletionService(this);
try {
ExecutionException ee = null;
//超时时间的nanos表示
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Iterator extends Callable> it = tasks.iterator();
//ExecutorCompletionService提交任务返回future,然后添加到集合中
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
for (;;) {
//轮询队列中已经完成的任务,弹出其future然后从队列中删除
Future f = ecs.poll();
//future为空,调用阻塞队列的take获取对应线程的执行结果
if (f == null) {
if (ntasks > 0) {
--ntasks;
futures.add(ecs.submit(it.next()));
++active;
}
else if (active == 0)
break;
else if (timed) {
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
nanos = deadline - System.nanoTime();
}
else
f = ecs.take();
}
//future不为空,get其结果
if (f != null) {
--active;
try {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
//执行任务集合,返回一个已经成功任务的结果(支持超时时间)
public T invokeAny(Collection extends Callable> tasks,long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
//doInvokeAny()
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
public T invokeAny(Collection extends Callable> tasks)
throws InterruptedException, ExecutionException {
try {
//doInvokeAny()
return doInvokeAny(tasks, false, 0);
} catch (TimeoutException cannotHappen) {
assert false;
return null;
}
}
执行给定任务,所有任务成功完成()则返回其future集合。源码如下:
//执行任务集合,返回任务的Future集合(支持超时时间)
public List> invokeAll(Collection extends Callable> tasks,long timeout, TimeUnit unit)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
long nanos = unit.toNanos(timeout);
//构造future集合
ArrayList> futures = new ArrayList>(tasks.size());
boolean done = false;
try {
for (Callable t : tasks)
//newTaskFor()将Callable类型转化为FutureTask类型,并添加到futures集合中
futures.add(newTaskFor(t));
final long deadline = System.nanoTime() + nanos;
final int size = futures.size();
//执行所有任务
for (int i = 0; i < size; i++) {
//这里调用execute()
execute((Runnable)futures.get(i));
nanos = deadline - System.nanoTime();
if (nanos <= 0L)
return futures;
}
//调用所有future的get,阻塞获取任务结果
for (int i = 0; i < size; i++) {
Future f = futures.get(i);
if (!f.isDone()) {
if (nanos <= 0L)
return futures;
try {
//FutureTask调用get获取任务结果
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
} catch (TimeoutException toe) {
return futures;
}
nanos = deadline - System.nanoTime();
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
public List> invokeAll(Collection extends Callable> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
ArrayList> futures = new ArrayList>(tasks.size());
boolean done = false;
try {
for (Callable t : tasks) {
RunnableFuture f = newTaskFor(t);
futures.add(f);
execute(f);
}
for (int i = 0, size = futures.size(); i < size; i++) {
Future f = futures.get(i);
if (!f.isDone()) {
try {
f.get();
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
}
一般线程池包含三部分:调度器、线程队列、任务队列。其中调度器将任务队列中的任务分配给线程队列中的线程去执行,执行完毕之后线程又会到线程队列中。
ThreadPoolExecutor是AbstractExecutorService的直接子类。提供了最基础的线程池功能。ThreadPoolExecutor就没有调度器,线程队列中的所有线程自动去获取任务队列中的任务进行执行。可见核心其实就是自动控制线程队列长度与任务队列长度相匹配,从而使任务按顺序合理执行。其中线程队列存放当前正在处理任务的线程或者空闲线程,任务队列存放待执行任务(正在被线程执行的任务是不在任务队列中的)。
类申明和部分成员如下,需要注意的是corePoolSize和maximumPoolSize两个线程容量相关的参数,以及任务队列和工作线程队列等成员,源码如下:
public class ThreadPoolExecutor extends AbstractExecutorService {
//任务队列
//存放提交成功的任务,但是还没有空闲线程来处理
private final BlockingQueue workQueue;
//重入锁,线程池内部操作需要使用
private final ReentrantLock mainLock = new ReentrantLock();
private final Condition termination = mainLock.newCondition();
//所有的工作线程(包含空闲的、非空闲的)
private final HashSet workers = new HashSet();
//记录线程池中包含过线程数量的最大值
private int largestPoolSize;
//记录已经完成的任务数
private long completedTaskCount;
//线程工厂,用于产生新线程
private volatile ThreadFactory threadFactory;
//拒绝处理器
private volatile RejectedExecutionHandler handler;
//线程最大空闲时间(线程一直空闲,超过这段时间则自动销毁)
private volatile long keepAliveTime;
//为true时,线程不会因为超过最大空闲时间而销毁,即keepAliveTime失效
private volatile boolean allowCoreThreadTimeOut;
//合理容量
private volatile int corePoolSize;
//最大容量
private volatile int maximumPoolSize;
//默认的拒绝添加新任务的处理器
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
//表示当前活跃线程数+线程池状态
//低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 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 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;//110
}
接下来是构造器,构造器对重要的几个变量进行初始化。首先解释一下线程数量自动调整的策略,使用corePoolSize(合理容量)、maximumPoolSize(最大容量)来控制线程队列的长度,每当调用execute(Runnable)提交新任务到线程池中会自动调整线程个数,就是如果来了新任务,线程优先增长到合理的个数,之后再来新任务则优先加入任务队列,任务队列放不下则线程个数增长到最大个数。如下:
如果还没超过合理容量:则需要新建线程来处理新任务
如果超过最合理容量且小于最大容量:任务队列未满则新任务放到任务队列中,任务队列满了则新建线程来处理新任务
如果等于最大容量:任务队列未满则新任务放到任务队列中,任务队列满了则执行拒绝策略(RejectedExecutionHandler )
构造器源码如下:
//构造器
//其他重载省略
public ThreadPoolExecutor(
int corePoolSize,//核心线程池容量
int maximumPoolSize,//线程池最大容量
long keepAliveTime,//线程池空闲时线程存活时间,超过时间的空闲线程会销毁
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;
}
申明一个内部类Worker,每个实例就是一个工作线程,每次调用execute()提交新任务时创建新线程就是Worker实例。Worker继承了AQS,AQS是一个实现了fifo的队列且提供了队列节点(也就是线程)的排队、阻塞、持锁调度等机制,后续再分析AQS源码。注意Worker的run()方法是直接调用了外部类的 runWorker(this)方法,传入当前工作线程实例然后与新建任务(也可能是从任务队列中拿到的)绑定,源码如下:
//工作线程
private final class Worker extends AbstractQueuedSynchronizer implements Runnable
{
final Thread thread;
//新提交的任务
Runnable firstTask;
volatile long completedTasks;
//传入新提交的任务
Worker(Runnable firstTask) {
//抑制interrupts信号
//runWorker中调度工作线程去真正执行任务时才开放次信号
setState(-1);
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
//run
public void run() {
//调用ThreadPoolExecutor.runWorker
//该方法时任务队列和线程队列的调度器,将任务分配给工作线程
runWorker(this);
}
//返回当前节点的持锁状态
//0:unlocked
//1:locked
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(),可以指明是否参考corePoolSize参数,该方法实现了自动调整Worker线程数量的具体逻辑,调用CAS获取当前工作线程数量、线程池状态,然后根据这几个参数判断新提交的任务是否需要新建工作线程来处理。源码如下:
//创建新线程执行新任务
//第二个参数表明是否考虑corePoolSize的影响
private boolean addWorker(Runnable firstTask, boolean core) {
//标记
retry:
for (;;) {
//ctl获取当前活跃线程数量、线程池状态信息,用c表示
int c = ctl.get();
//rs记录线程状态
int rs = runStateOf(c);
//如果线程池状态不符合,拒绝新建线程,拒绝执行新任务
if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && workQueue.isEmpty()))
return false;
//下面就是自动调整线程数量的逻辑
for (;;) {
//wc记录当前线程数量
int wc = workerCountOf(c);
//core记录是否考虑corePoolSize的影响
//true:wc只要没超过corePoolSize就允许向下执行(即下面的新建线程操作)
//falue:wc只要没超过maximumPoolSize就允许向下执行(即下面的新建线程操作)
if (wc >= CAPACITY ||wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//允许新建线程,调用CAS更新ctl,更新成功则从标记处跳出循环,向下执行
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get();
//允许新建线程,调用CAS更新ctl,更新失败则在线程状态未改变的情况下,跳到标记处重新循环
if (runStateOf(c) != rs)
continue retry;
}
}
//下面的try块就是新建工作线程的逻辑
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 {
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();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
接下来是提交任务的方法execute(),比较简单,就是判断是否需要新建线程直接执行任务,还是需要添加到任务队列里,还是要执行拒绝策略。源码如下:
//提交任务到线程池中
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//工作线程数量还没到核心数量
if (workerCountOf(c) < corePoolSize) {
//直接调用addWorker
if (addWorker(command, true))
return;
c = ctl.get();
}
//达到核心数量,且添加到任务队列成功
//workQueue.offer(command)向队列添加任务,成功返回true
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);
}
接下来是任务获取的方法getTask(),从任务队列中去轮询任务。依赖于BlockingQueue带超时的 poll方法。源码如下:
//带超时的poll轮询任务队列获取任务
//依赖与BlockingQueue带超时的 poll方法
private Runnable getTask() {
//默认未超时
boolean timedOut = false;
for (;;) {
int c = ctl.get();
//rs保存线程池状态信息
int rs = runStateOf(c);
//SHUTDOWN或STOP状态直接返回null
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
//ws保存当前工作线程数量
int wc = workerCountOf(c);
//超过allowCoreThreadTimeOut或者allowCoreThreadTimeOut允许超时,那么超时机制生效
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//调用BlockingQueue带超时的 poll方法获取队列中任务节点
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
然后是任务调度方法runWorker(),上一步getTask()从任务队列取出任务,这一步需要将任务分配给空闲线程去执行,前面的Woker类的run()方法会直接调用此方法并将工作线程实例自身传入。将一个工作线程与一个任务进行绑定,绑定方式是首先工作线程调用AQS的加锁代表正在处理任务,然后执行任务自己的run,最后工作线程调用AQS的解锁代表又变为空闲线程。源码如下:
//任务调度和执行
//作为调度器,联系任务队列和线程队列,将任务分配给工作线程
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
//w保存了当前被创建的工作线程
//task保存了创建当前工作线程时使用的新提交的任务
Runnable task = w.firstTask;
w.firstTask = null;
//开放工作线程的interrupts信号
w.unlock();
boolean completedAbruptly = true;
try {
//循环从任务队列获取任务
//getTask()使用带超时的poll轮询任务队列的任务
while (task != null || (task = getTask()) != null) {
//工作线程上锁,代表正在处理任务
w.lock();
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
//执行任务还是调用的任务自己的run
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);
}
}
接下来是停止所有工作线程interruptWorkers()、停止所有空闲线程interruptIdleWorkers()。首先线程队列中线程分为两种,一种是非空闲线程(即调用AQS上锁),另一种是空闲线程(即没有调用AQS上锁,tryLock()可以拿到锁)。同时空闲线程会阻塞在getTask()上去轮询任务,可以看到getTask()操作中没有上Worker锁。源码如下:
//停止所有工作线程
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
//上锁
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
//停止空闲的工作线程
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
//上锁
mainLock.lock();
try {
//遍历每个工作线程
for (Worker w : workers) {
Thread t = w.thread;
//工作线程还未设置终端标志,工作线程tryLock()获取AQS锁成功,这种工作线程才能中断
//工作线程继承了AQS,本身在runWorker()中工作线程跑任务时调用了lock()
//这也说明只有工作线程tryLock()获取AQS锁成功才算空闲线程
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
//为true则只中断一个,tryTerminate()中会用到
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
中断线程池方法shutdown()、shutdownNow()。他们利用了上诉两个方法,前者先中断所有空闲线程,停止提交新任务,然后等待工作线程任务执行完毕,再调用tryTerminate()循环中断刚刚执行完任务变为空闲线程的工作线程。后者直接中断所有线程,返回队列上的任务(也就是没有被执行的任务),源码如下:
//关闭线程池
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
//SHUTDOWN
//这个状态不能再提交新任务,但是已经提交的任务会让他执行完
advanceRunState(SHUTDOWN);
//中断所有空闲线程
interruptIdleWorkers();
onShutdown();
} finally {
mainLock.unlock();
}
//上面停止了所有的空闲线程
//此时如果有非空闲线程执行完了任务,变为空闲线程,需要再次中断这些刚刚空闲先来的工作线程
//tryTerminate()就是"补漏"的,他利用for循环,每次中断一个在上一步没有被中断的线程
tryTerminate();
}
//关闭线程池
//返回未执行的任务集合
public List shutdownNow() {
List tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
//STOP
//这个状态不能再提交新任务
advanceRunState(STOP);
//中断所有线程,不过也只是让正在运行的工作线程打上标记,任务也不是直接停止
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
//同样也是"补漏"
tryTerminate();
return tasks;
}
最后tryTerminate()方法,上面说到这个方法用来“补漏”,也就是利用for循环,每次循环会中断一个空闲线程,这个空闲线程可能是刚刚执行完任务从非空闲状态转为空闲状态(所以在shutdown()中没有被中断)。在所有需要中断线程池的地方都插入次方法,如果线程池已经进入终止流程,没有任务等待执行了,但线程池还有线程,保证这些线程能被中断处理。注意线程池状态、线程数量等都是调用CAS获取的。源码如下:
//尝试停止线程池
//这个方法可以用来"补漏"
final void tryTerminate() {
//这个循环能够跑多次的条件是
for (;;) {
int c = ctl.get();
//判断线程池是否需要终止
//3中情况任一为true则直接return,不进行终止
//1、还在运行状态
//2、状态是TIDYING、或 TERMINATED,已经终止过了
//3、SHUTDOWN 且 workQueue不为空
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
//shutdown状态 且 workQueue为空,或者 stop状态,但是还有未中断的空闲线程(上一次中断时他正在执行任务)
//如果此时线程池还有线程(正在运行任务,正在等待任务),中断一个正在等任务的空闲线程
if (workerCountOf(c) != 0) {
interruptIdleWorkers(ONLY_ONE);
//进入下一次循环
return;
}
//如果状态是SHUTDOWN,workQueue也为空了,正在运行的worker也没有了,开始terminated
//下面是正式的关闭线程池逻辑
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//CAS:将线程池的ctl变成TIDYING(所有的任务被终止,workCount为0,为此状态时将会调用terminated()方法),期间ctl有变化就会失败,会再次for循环
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();//子类实现
} finally {
//将线程池的ctl变成TERMINATED
ctl.set(ctlOf(TERMINATED, 0));
//唤醒调用了 等待线程池终止的线程 awaitTermination()
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// 如果上面的CAS判断false,再次循环
}
}
前面说到任务队列满了,工作线程已经到了最大数量,新来的任务需要拒绝提交,默认实现了四种拒绝策略。分别是有下面几种:
CallerRunsPolicy:跑execute()的线程直接去跑任务的run()
AbortPolicy:直接抛出异常
DiscardPolicy:直接忽略本次被拒绝的任务
DiscardOldestPolicy:从任务队列中poll()一个任务丢弃掉,然后尝试exectue()提交本次任务
源码也比较简单,源码如下:
//拒绝提交任务策略的handler
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
//跑execute()的线程,这个线程直接跑任务
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);
}
}
}
余下是一些简单函数、辅助函数等等。包括execute()扩展接口、CTL的CAS支持等等。源码如下:
//runWorker()中调用task的run()的前后会调用这两个方法
//交给子类进行扩展
protected void beforeExecute(Thread t, Runnable r) { }
protected void afterExecute(Runnable r, Throwable t) { }
//tryTerminate()的后半部分正式中断线程池逻辑中会调用
//交给子类扩展
protected void terminated() { }
//CTL变量的CAS支持
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()));
}
//获取任务数量
public long getTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers) {
//工作线程已经完成的任务数量
n += w.completedTasks;
//工作线程如果上锁说明正在跑任务,所以加一
if (w.isLocked())
++n;
}
//再加上还未执行的队列中任务
return n + workQueue.size();
} finally {
mainLock.unlock();
}
}
//弹出队列中的任务
//ShutdownNow会调用此方法,中断线程池并返回未执行的任务
private List drainQueue() {
BlockingQueue q = workQueue;
ArrayList taskList = new ArrayList();
q.drainTo(taskList);
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
//工作线程退出的收尾工作
//runWorker()中如果getTask()返回null或者在用户task.run过程中有异常出现时需要对线程退出做收尾工作
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly)
//工作线程数量减一
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
//从队列中删除该工作线程
workers.remove(w);
} finally {
mainLock.unlock();
}
//补漏函数
tryTerminate();
int c = ctl.get();
//线程池不在停止状态中
if (runStateLessThan(c, STOP)) {
//线程正常退出
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return;
}
//用户异常退出,或者线程数量小于需要维护的数量,补充工作线程
addWorker(null, false);
}
}
//从队列中删除指定任务
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
tryTerminate();
return removed;
}
//启动一个线程
public boolean prestartCoreThread() {
//这里确保核心数量参数影响下创建新工作线程,然后跑一个null任务
return workerCountOf(ctl.get()) < corePoolSize && addWorker(null, true);
}
//确保成功启动一个线程
void ensurePrestart() {
int wc = workerCountOf(ctl.get());
if (wc < corePoolSize)
addWorker(null, true);
else if (wc == 0)
addWorker(null, false);
}
//启动所有线程
public int prestartAllCoreThreads() {
int n = 0;
while (addWorker(null, true))
++n;
return n;
}
//清空任务队列
public void purge() {
final BlockingQueue q = workQueue;
try {
Iterator it = q.iterator();
while (it.hasNext()) {
Runnable r = it.next();
if (r instanceof Future> && ((Future>)r).isCancelled())
it.remove();
}
} catch (ConcurrentModificationException fallThrough) {
for (Object r : q.toArray())
if (r instanceof Future> && ((Future>)r).isCancelled())
q.remove(r);
}
tryTerminate();
}
首先查看,队列接口,阻塞队列接口,源码如下:
//队列
//提供两种操作失败策略
//第一种,操作失败抛出异常
//第二种,操作失败返回null或false
public interface Queue extends Collection {
//添加元素(失败抛出异常)
boolean add(E e);
//删除头元素(失败抛出异常)
E remove();
//查看头元素(失败抛出异常)
E element();
//添加元素(失败返回null或false)
boolean offer(E e);
//弹出头元素(失败返回null或false)
E poll();
//弹出头元素(失败返回null或false)
E peek();
}
//阻塞队列
//增加了阻塞直到成功的失败策略
//为什么需要阻塞队列
public interface BlockingQueue extends Queue {
//添加元素(失败抛出异常)
boolean add(E e);
//添加元素(失败返回true)
boolean offer(E e);
//添加元素(失败则阻塞等待一段时间,直到有队列空位)
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;
//添加元素(失败则阻塞等待,直到有队列空位)
void put(E e) throws InterruptedException;
//弹出头元素(失败则阻塞等待,直到有元素可有弹出)
E take() throws InterruptedException;
//弹出头元素(失败则阻塞等待一段时间,直到有元素可有弹出)
E poll(long timeout, TimeUnit unit) throws InterruptedException;
//剩余容量
int remainingCapacity();
//删除指定元素(失败抛出异常)
boolean remove(Object o);
//检查包含指定元素
public boolean contains(Object o);
//删除队列所有元素,并添加到指定集合中
int drainTo(Collection super E> c);
//删除队列n个元素,并添加到指定集合中
int drainTo(Collection super E> c, int maxElements);
}
LinkedBlockingQueue实现了一个可阻塞的fifo链表队列。相关方法基于双锁实现线程安全,takeLock(出队锁)、putLock(入队锁),允许出队、入队并行,但是其他操作需要上双锁比如remove()、contains()、toArray()、toString()、clear()、drainTo()、writeObject()等等。在大部分并发场景下,LinkedBlockingQueue的吞吐量比ArrayBlockingQueue更好。利用ReentrantLock()的lock()和lockInterruptibly()实现阻塞式获取锁。
类申明,部分成员。节点类实现链表结构,申明了两个ReentrantLock()锁进行读写的并发控制,申明了两个Condition用于线程通信。 源码如下:
public class LinkedBlockingQueue
extends AbstractQueue
implements BlockingQueue, java.io.Serializable {
//队列长度
//默认无界Integer.MAX_VALUE
private final int capacity;
//队列元素个数
private final AtomicInteger count = new AtomicInteger();
//头结点(不存放数据,item为空)
transient Node head;
//尾结点(不存放数据,item为空)
private transient Node last;
//出队锁,用于take等操作
private final ReentrantLock takeLock = new ReentrantLock();
//出队条件
private final Condition notEmpty = takeLock.newCondition();
//入队锁,用于put等操作
private final ReentrantLock putLock = new ReentrantLock();
//入队条件
private final Condition notFull = putLock.newCondition();
//链表节点
static class Node {
//节点数据
E item;
//后继,默认为null
Node next;
Node(E x) { item = x; }
}
}
构造函数,队列长度、初始化集合进行重载,源码如下:
//构造器
//默认长度为最大值
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
//指定队列长度
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node(null);
}
//用指定集合创建阻塞队列,迭代器顺序相同
public LinkedBlockingQueue(Collection extends E> c) {
this(Integer.MAX_VALUE);
//获取入队锁
final ReentrantLock putLock = this.putLock;
//上锁,这里虽然上了锁但是对其他竞争者保留可见性
putLock.lock();
try {
int n = 0;
for (E e : c) {
//使用集合创建队列,不能存放null元素
if (e == null)
throw new NullPointerException();
if (n == capacity)
throw new IllegalStateException("Queue full");
//挨个链接每个元素到队列尾部
enqueue(new Node(e));
++n;
}
count.set(n);
} finally {
//解锁
putLock.unlock();
}
}
一些基本方法、工具函数,比如入队、出队、线程通信、双锁、删除元素、清空链表等等。源码如下:
//入队工具函数:连接到队列尾部
private void enqueue(Node node) {
last = last.next = node;
}
//出队工具函数:弹出队列第一个元素
private E dequeue() {
//头结点不保存数据
Node h = head;
//头结点的后继才保存数据,需要弹出
Node first = h.next;
//断开旧头结点,帮助GC
h.next = h;
//旧头结点的后继就是新头结点
head = first;
//返回新头结点元素,之后置空
E x = first.item;
first.item = null;
return x;
}
//唤醒出队阻塞的线程
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
//唤醒在条件notEmpty上阻塞的线程
notEmpty.signal();
} finally {
takeLock.unlock();
}
}
//唤醒入队阻塞的线程
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
//唤醒在条件notFull上阻塞的线程
notFull.signal();
} finally {
putLock.unlock();
}
}
//上双锁
//入队锁、出队锁
//这个操作在后面大部分方法中都需要,比如remove()、contains()、toArray()、toString()、clear()、drainTo()、writeObject()等等
void fullyLock() {
putLock.lock();
takeLock.lock();
}
//解双锁
//出队、入队
void fullyUnlock() {
takeLock.unlock();
putLock.unlock();
}
//返回队列元素个数
public int size() {
return count.get();
}
//返回队列剩余容量
public int remainingCapacity() {
return capacity - count.get();
}
//断开p
//这里传入的p是trail的后继,p是待删除的节点
void unlink(Node p, Node trail) {
//断开p
p.item = null;
trail.next = p.next;
if (last == p)
last = trail;
if (count.getAndDecrement() == capacity)
notFull.signal();
}
//删除元素
//需要上双锁
public boolean remove(Object o) {
if (o == null) return false;
fullyLock();
try {
//向后遍历链表
for (Node trail = head, p = trail.next;
p != null;
trail = p, p = p.next) {
//找到待删除元素
if (o.equals(p.item)) {
unlink(p, trail);
return true;
}
}
return false;
} finally {
fullyUnlock();
}
}
//清空链表
//需要上双锁
public void clear() {
fullyLock();
try {
for (Node p, h = head; (p = h.next) != null; h = p) {
h.next = h;
p.item = null;
}
//直接头尾指向同一个节点
head = last;
if (count.getAndSet(0) == capacity)
notFull.signal();
} finally {
fullyUnlock();
}
}
下面是阻塞式的入队操作,利用入队锁ReentrantLock的lockInterruptibly()、lock()上锁实现阻塞。源码如下:
//入队
//会阻塞直到成功,允许其他线程对本线程打中断标记而抛出异常
//调用lockInterruptibly()上锁
public void put(E e) throws InterruptedException {
//元素不能为null
if (e == null) throw new NullPointerException();
//c记录队列元素
int c = -1;
Node node = new Node(e);
//队列锁
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
//三种上锁方式:
//1.lock():调用后一直阻塞到获得锁
//2.tryLock():获取锁成功或失败直接返回结果
//3.lockInterruptibly():调用后一直阻塞到获得锁,但是接收中断信号,接收到信号之后直接抛出异常而不考虑是否拿到锁
putLock.lockInterruptibly();
try {
//队满,所有想要入队的线程等待
while (count.get() == capacity) {
notFull.await();
}
//队不满,当前线程进行入队操作
enqueue(node);
c = count.getAndIncrement();
//队列依然不满,唤醒其他想要入队的线程
if (c + 1 < capacity)
notFull.signal();
} finally {
//当前线程入队操作成功后解锁
putLock.unlock();
}
//如果 c = 0
//说明 c = count.getAndIncrement() 执行之前 count为-1
//即队列之前为空,当前线程入队操作之后队列不再为空,则唤醒出队阻塞的线程
if (c == 0)
signalNotEmpty();
}
//入队
//会阻塞直到成功
//调用lock上锁
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
if (count.get() == capacity)
return false;
int c = -1;
Node node = new Node(e);
final ReentrantLock putLock = this.putLock;
//这里与put()有区别
//lock():不考虑中断标志,不管怎么样都必须等到获取锁成功
putLock.lock();
try {
if (count.get() < capacity) {
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
}
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return c >= 0;
}
//入队
//会阻塞直到成功,可以设置等待时间,接收到中断信号会抛出异常退出,超过等待时间会返回false退出
//调用lockInterruptibly()上锁
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
long nanos = unit.toNanos(timeout);
int c = -1;
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
//队满
while (count.get() == capacity) {
//超过等待时间,放弃入队操作,直接返回false
if (nanos <= 0)
return false;
//所有想入队的线程等待指定时间
nanos = notFull.awaitNanos(nanos);
}
//队不满,入队
enqueue(new Node(e));
c = count.getAndIncrement();
//队仍然不满,唤醒其他想要入队的线程
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return true;
}
下面是阻塞式的出啦队操作,利用入队锁ReentrantLock的lockInterruptibly()、lock()上锁实现阻塞。源码如下:
//出队
//会阻塞直到成功,可接收中断标记而抛出异常退出
//调用lockInterruptibly()上锁
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
//队空
while (count.get() == 0) {
//所有想出队线程等待
notEmpty.await();
}
x = dequeue();//出队
c = count.getAndDecrement();
//队仍然不空
if (c > 1)
//唤醒其他想出队线程
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
//出队
//会阻塞直到成功,可设置等待时间,可接收中断标记而抛出异常退出,超过等待时间返回false退出
//调用lockInterruptibly()上锁
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
E x = null;
int c = -1;
long nanos = unit.toNanos(timeout);
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
//出队
//会阻塞直到成功
//调用lock()上锁
public E poll() {
final AtomicInteger count = this.count;
if (count.get() == 0)
return null;
E x = null;
int c = -1;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
if (count.get() > 0) {
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
}
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
//弹出,但队列中不删除
//会阻塞直到成功
//调用lock()上锁
public E peek() {
if (count.get() == 0)
return null;
final ReentrantLock takeLock = this.takeLock;
//上锁
takeLock.lock();
try {
//弹出队列第一个元素
//不同点在于:dequeue()断开旧头结点,帮助GC
//h.next = h;
//而此处没有删除队列元素
Node first = head.next;
if (first == null)
return null;
else
return first.item;
} finally {
takeLock.unlock();
}
}
//弹出队列n个元素,添加到集合中
public int drainTo(Collection super E> c, int maxElements) {
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
return 0;
boolean signalNotFull = false;
//依然使用出队锁
final ReentrantLock takeLock = this.takeLock;
//lock()上锁
takeLock.lock();
try {
int n = Math.min(maxElements, count.get());
Node h = head;
int i = 0;
try {
//弹出n个元素到集合中
while (i < n) {
Node p = h.next;
c.add(p.item);
p.item = null;
h.next = h;
h = p;
++i;
}
return n;
} finally {
if (i > 0) {
head = h;
signalNotFull = (count.getAndAdd(-i) == capacity);
}
}
} finally {
takeLock.unlock();
if (signalNotFull)
signalNotFull();
}
}
迭代器,迭代是上双锁的,源码如下:
//迭代器
public Iterator iterator() {
return new Itr();
}
private class Itr implements Iterator {
//记录当前被操作的节点
private Node current;
//记录最近被操作的节点
private Node lastRet;
//当前节点元素
private E currentElement;
Itr() {
//构造迭代器也要上双锁
fullyLock();
try {
current = head.next;
if (current != null)
currentElement = current.item;
} finally {
fullyUnlock();
}
}
public boolean hasNext() {
return current != null;
}
private Node nextNode(Node p) {
for (;;) {
Node s = p.next;
if (s == p)
return head.next;
if (s == null || s.item != null)
return s;
p = s;
}
}
//迭代需要上双锁
public E next() {
fullyLock();
try {
if (current == null)
throw new NoSuchElementException();
E x = currentElement;
//更新最近访问的节点
lastRet = current;
//更新当前访问节点
current = nextNode(current);
//更新当前访问节点元素
currentElement = (current == null) ? null : current.item;
return x;
} finally {
fullyUnlock();
}
}
//删除结点
public void remove() {
if (lastRet == null)
throw new IllegalStateException();
//同样上双锁
fullyLock();
try {
//node最近被访问的节点
Node node = lastRet;
lastRet = null;
//遍历队列
for (Node trail = head, p = trail.next;
p != null;
trail = p, p = p.next) {
//找到node则删除
if (p == node) {
unlink(p, trail);
break;
}
}
} finally {
fullyUnlock();
}
}
}
并行迭代器。源码如下:
//并行迭代器
public Spliterator spliterator() {
return new LBQSpliterator(this);
}
static final class LBQSpliterator implements Spliterator {
static final int MAX_BATCH = 1 << 25; // max batch array size;
final LinkedBlockingQueue queue;
Node current; // current node; null until initialized
int batch; // batch size for splits
boolean exhausted; // true when no more nodes
long est; // size estimate
LBQSpliterator(LinkedBlockingQueue queue) {
this.queue = queue;
this.est = queue.size();
}
public long estimateSize() { return est; }
public Spliterator trySplit() {
Node h;
final LinkedBlockingQueue q = this.queue;
int b = batch;
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
if (!exhausted &&
((h = current) != null || (h = q.head.next) != null) &&
h.next != null) {
Object[] a = new Object[n];
int i = 0;
Node p = current;
q.fullyLock();
try {
if (p != null || (p = q.head.next) != null) {
do {
if ((a[i] = p.item) != null)
++i;
} while ((p = p.next) != null && i < n);
}
} finally {
q.fullyUnlock();
}
if ((current = p) == null) {
est = 0L;
exhausted = true;
}
else if ((est -= i) < 0L)
est = 0L;
if (i > 0) {
batch = i;
return Spliterators.spliterator
(a, 0, i, Spliterator.ORDERED | Spliterator.NONNULL |
Spliterator.CONCURRENT);
}
}
return null;
}
public void forEachRemaining(Consumer super E> action) {
if (action == null) throw new NullPointerException();
final LinkedBlockingQueue q = this.queue;
if (!exhausted) {
exhausted = true;
Node p = current;
do {
E e = null;
q.fullyLock();
try {
if (p == null)
p = q.head.next;
while (p != null) {
e = p.item;
p = p.next;
if (e != null)
break;
}
} finally {
q.fullyUnlock();
}
if (e != null)
action.accept(e);
} while (p != null);
}
}
public boolean tryAdvance(Consumer super E> action) {
if (action == null) throw new NullPointerException();
final LinkedBlockingQueue q = this.queue;
if (!exhausted) {
E e = null;
q.fullyLock();
try {
if (current == null)
current = q.head.next;
while (current != null) {
e = current.item;
current = current.next;
if (e != null)
break;
}
} finally {
q.fullyUnlock();
}
if (current == null)
exhausted = true;
if (e != null) {
action.accept(e);
return true;
}
}
return false;
}
public int characteristics() {
return Spliterator.ORDERED | Spliterator.NONNULL |
Spliterator.CONCURRENT;
}
}
AQS是整个并发框架里面锁的核心,给出了一个抽象阻塞队列同步器,用一个state表示竞争资源,队列中头结点的后续节点排队等待。AQS中已经实现好了同步队列节点的维护(出队入队、删除等等),条件队列节点的维护(用于模拟线程通信),实现了独占和共享两种方式的获取逻辑(同步队列入队以及线程挂起)、释放逻辑(同步队列出队以及线程唤醒),而其子类扩展四个方法则做两件事情:1、通过CAS对资源加减或者0/1赋值操作,2、获取逻辑返回正/负数用于AQS判断是否需要加入同步队列进行挂起,释放逻辑返回true/false用于AQS判断是否需要唤醒同步队列的节点。比如locks包下面的ReentrantLock、Semaphore、CountDownLatch等都有一个Sync(AQS子类)引用用于实现不同功能。大概原理图如下:
上图展示的独占模式的锁实现,使用state=0/1来表明资源是否被占用。共享模式使用一个整数state=n来表示资源个数,某个节点(线程)调用acquire(m)会一次性获取m个许可对应着state=n-m,某个线程Thread(5)需要5个许可但是state小于5那么这个线程尝试获取锁失败,加入同步队列利用自旋和CAS阻塞等待。
比如Semaphore(10)构造时,AQS的state=10,然后每个线程调用semaphore.acquire()获取锁就会使得state减一,同样释放锁release()会使的state加1,这样控制某个任务在acquire()和release()中间的代码只能由10个线程同时执行。
AQS的源码可以划分为几个部分,如下:
(1)Node部分:实现了CHL结构的链表节点
(2)Conditions:实现了基于锁条件的线程通信
(3)CAS、工具函数部分:实现了资源变量state、节点状态waitState等变量、队列节点的CAS操作的逻辑。以及后续操作的工具函数
(4)acquire部分:实现了独占方式获取资源的逻辑
(5)acquireShared部分:实现了共享方式获取资源的逻辑
(6)release部分:实现了独占方式释放资源的逻辑
(7)releaseShared部分:实现了共享方式释放资源的逻辑
Node部分:
这个成员内部类实现了一个双链表结构,而外部类AQS持有head、tail两个节点,其中head是一个空节点,tail是队尾节点用于插入其他节点。值的注意的是由head和tail构成的队列是同步队列,这个队列中的节点绑定的线程是那些有资格进行资源竞争的线程,由于竞争失败则进入队列自旋或者被park( )挂起,等待被唤醒再次参与竞争。而成员内部类Condition自己维护了一个条件等待队列,这个队列里面放的是没有资格竞争资源的节点,在某个节点已经持有资源的同时想要放弃资源,所以使用Condition调用await( )让自己释放资源,然后把自己放到条件等待队列中,等待同步队列中下一个持有资源的节点使用Condition调用signal( )将自己唤醒,唤醒的结果是转移到同步队列中参与下一次竞争(所以状态仍然是自旋或者park()阻塞而不是直接唤醒或者直接拿到资源,这也符合Object的notify()的语义),Condition这两个操作的前提是必须持有资源,比如在ReentrantLock的lock()和unlock()之间才能调用。因此同步队列可以实现synchronized的线程安全功能类似功能,条件等待队列实现Object的notify()/wait()的线程通信的类似功能。
另一点,node使用EXCLUSIVE标记是独占还是共享。waitStatus标记节点状态,同步队列中节点状态只能是1(绑定的线程已经取消)、-1(需要唤醒后续节点)、-3(需要唤醒后续节点且允许向后传播),这样直接以0为分界可以判断队列中结点是否是有效节点。在条件等待队列中的节点状态只能是1(绑定的线程已经取消)、-2(绑定的线程正在等待某个条件队列中等待某condition)。waitStatus这个变量比较重要,比如尝试获取资源失败的节点会插入到同步队列队尾然后移动最后进入等待(自旋/park()),移动到一个waitStatus=-1的节点后面,这样保证这个节点能被前趋节点调用unpark()唤醒。
源码还是比较简单易懂,如下:
public class Node {
//双链表结构
static final class Node {
//状态
static final Node SHARED = new Node();
//独占标记
static final Node EXCLUSIVE = null;
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
//当前节点的等待状态
//1(绑定的线程已经取消)、-1(需要唤醒后续节点)、-2(绑定的线程正在等待某个条件队列中等待某condition)、-3(需要唤醒后续节点且允许向后传播)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
//与当前节点绑定的线程
volatile Thread thread;
//条件等待队列的下一个节点
Node nextWaiter;
final boolean isShared() {
return nextWaiter == SHARED;
}
//返回前趋
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() {}
//绑定线程、资源是否共享(addWaiter使用,用于插入同步队列)
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
//绑定线程、等待状态(Condition使用,用于插入等待队列)
Node(Thread thread, int waitStatus) {
this.waitStatus = waitStatus;
this.thread = thread;
}
}
}
Conditions部分:
上面说了,这个成员内部类用来模拟线程通信,但是从本质上说同步队列、条件等待队列都使用的是Node节点,只是其waitstatus参数取值不一样,并且Node绑定的线程的真实状态(running、runnable、blocked)与节点在哪个队列上无关,因为只有同步队列的头节点是拿到锁正在跑任务,而其他节点都在等待(自旋/park()挂起)。这里仅仅只是从逻辑上面区分哪些有竞争资格哪些没有竞争资格,有资格的线程可以排队等AQS为他们分配锁,没资格的线程只能等别人唤醒自己才能去排队,这符合Object的wait()、notify()的语义,因为notify()也只是让线程参与锁竞争即却并不是立即转为可运行状态。我猜Object的notify是将线程从BlockQueue转移到WaitQueue,而WaitQueue也分为两部分(有竞争资格和无竞争资格),这里Condition与jvm实现方式思路一致。
源码同样比较简单易读,如下:
public class ConditionObject implements Condition, java.io.Serializable {
//条件等待队列的头、尾结点
private transient Node firstWaiter;
private transient Node lastWaiter;
//构造器
public ConditionObject() { }
//创建节点,绑定当前线程,添加到条件等待队列的队尾
private Node addConditionWaiter() {
Node t = lastWaiter;
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
//清除CONDITION状态的节点(既不想竞争又不想等待的节点即线程销毁的节点)
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
//遍历所有,CONDITION节点则断开
while (t != null) {
Node next = t.nextWaiter;
if (t.waitStatus != Node.CONDITION) {
t.nextWaiter = null;
if (trail == null)
firstWaiter = next;
else
trail.nextWaiter = next;
if (next == null)
lastWaiter = trail;
}
else
trail = t;
t = next;
}
}
//唤醒一个节点(条件队列上的)参与锁竞争
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
//移动第一个节点
doSignal(first);
}
//唤醒所有节点(条件队列上的)参与锁竞争
public final void signalAll() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
//移动第一个节点到同步队列上
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
//transferForSignal()会调用enq()将节点添加到同步对了,修改waitStatus为SIGNAL
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
//移动所有节点到同步队列上
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
do {
Node next = first.nextWaiter;
first.nextWaiter = null;
transferForSignal(first);
first = next;
} while (first != null);
}
//停止线程
//这种停止在signal()、signalAll()、Thread.interrupt()、伪wakeup下能够唤醒
public final void await() throws InterruptedException {
//这里是可中断的支持,检测到中断标志直接抛出异常交给外部处理,不再执行后续逻辑(比如追加到条件队列失去竞争资格)
if (Thread.interrupted())
throw new InterruptedException();
//先添加到条件等待队列尾部
Node node = addConditionWaiter();
//释放该节点资源
int savedState = fullyRelease(node);
int interruptMode = 0;
//节点在同步队列则跳过,如果不在则执行循环并调用park()挂起
while (!isOnSyncQueue(node)) {
//这里挂起,直到许可可用,注意许可只有一个不能叠加所以这里循环是没问题的
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
//节点由于signal操作从等待队列转移到了同步队列中才能跳过循环走到这里
//acquireQueued()是让该节点自旋转获取资源,并移动到Signal节点后
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
//停止线程
//同上,但不响应中断
public final void awaitUninterruptibly() {
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if (Thread.interrupted())
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted)
selfInterrupt();
}
//停止线程
//指定超时时间
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return deadline - System.nanoTime();
}
//停止线程
//指定deadline
public final boolean awaitUntil(Date deadline)
throws InterruptedException {
long abstime = deadline.getTime();
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (System.currentTimeMillis() > abstime) {
timedout = transferAfterCancelledWait(node);
break;
}
LockSupport.parkUntil(this, abstime);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
//停止线程
//指定超时时间
public final boolean await(long time, TimeUnit unit)
throws InterruptedException {
long nanosTimeout = unit.toNanos(time);
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
timedout = transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
private static final int REINTERRUPT = 1;
//用于抛出异常,线程直接exit退出,不再参与AQS上面的状态转换
private static final int THROW_IE = -1;
//检查wait状态下节点绑定线程的中断标志
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
//已经被标注中断则抛出异常,没有则先标记
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
if (interruptMode == THROW_IE)
throw new InterruptedException();
else if (interruptMode == REINTERRUPT)
selfInterrupt();
}
final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {
return sync == AbstractQueuedSynchronizer.this;
}
//检查条件等待队列上是否有等待者
protected final boolean hasWaiters() {
//当前线程先必须持有资源,没有则抛出异常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//找到waitStatus为CONDITION返回true
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION)
return true;
}
return false;
}
//获取条件等待队列长度
protected final int getWaitQueueLength() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int n = 0;
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION)
++n;
}
return n;
}
//返回条件等待队列上的所有线程
protected final Collection getWaitingThreads() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
ArrayList list = new ArrayList();
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION) {
Thread t = w.thread;
if (t != null)
list.add(t);
}
}
return list;
}
}
CAS、工具函数部分:
因为真正的(尝试)获取锁、(尝试)释放锁、共享和独占等重要核心逻辑在后续的部分,先分析一下要用到的相关函数。包括同步队列的head、tail节点的CAS操作,节点状态waitStatus的CAS操作,资源的CAS操作,AQS相关成员,资源访问的工具函数,交给子类扩展的空方法等等。
首先封装了CAS内部类,以及成员函数,源码如下:
public class CAS {
//CAS支持
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long stateOffset;
private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;
private static final long nextOffset;
static {
try {
stateOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
headOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
tailOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
waitStatusOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("waitStatus"));
nextOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("next"));
} catch (Exception ex) { throw new Error(ex); }
}
//head的CAS操作
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
//tail的CAS操作
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
//WaitStatus的CAS操作
private static final boolean compareAndSetWaitStatus(Node node,int expect,int update) {
return unsafe.compareAndSwapInt(node, waitStatusOffset,expect, update);
}
//Next的CAS操作
private static final boolean compareAndSetNext(Node node,Node expect,Node update) {
return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}
}
AQS的重要成员,函数,源码如下:
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
//队列:
//多线程争用资源被阻塞时会进入此队列
//头结点占用资源,后续所有节点阻塞并排队等待资源
private transient volatile Node head;
private transient volatile Node tail;
//0:独占时,资源未被线程占有
//1:独占式,资源被某线程占有
//n:共享时,资源的剩余量
private volatile int state;
//资源的三种操作方式,
protected final int getState() {
return state;
}
protected final void setState(int newState) {
state = newState;
}
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
//获取资源(独占):成功失败返回boolean值
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
//释放资源(独占):成功失败返回boolean值
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
//获取资源(共享):失败返回负数,成功且剩余可用资源返回正数,成功不剩余可用资源返回0
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
//释放资源(共享):允许唤醒后续等待节点返回true,不允许返回false
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
//检测当前线程是否独占资源:
protected boolean isHeldExclusively() {
throw new UnsupportedOperationException();
}
//添加一个等待节点到同步队列队尾
private Node addWaiter(Node mode) {
//每个节点与创建节点的当前线程绑定,mode指明是独占还是共享
Node node = new Node(Thread.currentThread(), mode);
//直接方式插入队尾,利用的是旧尾结点的前趋
Node pred = tail;
if (pred != null) {
//旧尾结点成为传入节点的前趋
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//直接插入方式失败,则用遍历的方式插入
enq(node);
return node;
}
//添加结点到同步队列队尾
private Node enq(final Node node) {
//这里是遍历的方式找到队尾插入,并返回该节点
for (;;) {
Node t = tail;
if (t == null) {
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
//节点出队
private void cancelAcquire(Node node) {
if (node == null)
return;
//传入节点清除绑定线程
node.thread = null;
Node pred = node.prev;
//跳过前面的waitStatus为1(CANCELLED)的节点
while (pred.waitStatus > 0)
//向前遍历
node.prev = pred = pred.prev;
//找到一个有效节点
Node predNext = pred.next;
//将传入节点waitStatus标记为CANCELLED
node.waitStatus = Node.CANCELLED;
//场景1:node为tail:直接更新尾节点即可
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
int ws;
//场景2:node既不是tail,也不是head的后继:则将前趋waitStatus标记为SIGNAL并移动指针将node移除队列
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
//场景3:node是head的后继:则唤醒node的后继
unparkSuccessor(node);
}
node.next = node;
}
}
//给自身打上中断标记
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
//判断同步队列中是否有想要竞争资源的节点
public final boolean hasQueuedThreads() {
return head != tail;
}
//判断同步队列是否为空
public final boolean hasContended() {
return head != null;
}
//返回同步队列第一个线程
public final Thread getFirstQueuedThread() {
return (head == tail) ? null : fullGetFirstQueuedThread();
}
private Thread fullGetFirstQueuedThread() {
Node h, s;
Thread st;
if (((h = head) != null && (s = h.next) != null &&
s.prev == head && (st = s.thread) != null) ||
((h = head) != null && (s = h.next) != null &&
s.prev == head && (st = s.thread) != null))
return st;
Node t = tail;
Thread firstThread = null;
while (t != null && t != head) {
Thread tt = t.thread;
if (tt != null)
firstThread = tt;
t = t.prev;
}
return firstThread;
}
//判断线程是否是同步队列中的线程
public final boolean isQueued(Thread thread) {
if (thread == null)
throw new NullPointerException();
for (Node p = tail; p != null; p = p.prev)
if (p.thread == thread)
return true;
return false;
}
//头节点不为空,并头节点的下一个节点不为空,并且不是共享模式【独占模式,写锁】,并且线程不为空,则返回true。
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
//通过判断"当前线程"是不是在CLH队列的队首,来返回AQS中是不是有比“当前线程”等待更久的线程。
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
}
//获取同步队列长度
public final int getQueueLength() {
int n = 0;
for (Node p = tail; p != null; p = p.prev) {
if (p.thread != null)
++n;
}
return n;
}
//获取同步队列上所有节点绑定的线程
public final Collection getQueuedThreads() {
ArrayList list = new ArrayList();
for (Node p = tail; p != null; p = p.prev) {
Thread t = p.thread;
if (t != null)
list.add(t);
}
return list;
}
//获取所有独占模式节点绑定的线程
public final Collection getExclusiveQueuedThreads() {
ArrayList list = new ArrayList();
for (Node p = tail; p != null; p = p.prev) {
if (!p.isShared()) {
Thread t = p.thread;
if (t != null)
list.add(t);
}
}
return list;
}
//获取所有共享模式节点绑定的线程
public final Collection getSharedQueuedThreads() {
ArrayList list = new ArrayList();
for (Node p = tail; p != null; p = p.prev) {
if (p.isShared()) {
Thread t = p.thread;
if (t != null)
list.add(t);
}
}
return list;
}
//检查是否在同步队列中
final boolean isOnSyncQueue(Node node) {
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
//有后继,那么一定在队列中
if (node.next != null)
return true;
return findNodeFromTail(node);
}
private boolean findNodeFromTail(Node node) {
//从同步队列后面向前找
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
//移动条件队列中被signal的节点到同步队列上
final boolean transferForSignal(Node node) {
//waitStatus改变失败,说明节点CONDITION掉了
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
//将节点插入到同步队列的队尾
Node p = enq(node);
int ws = p.waitStatus;
//修改waitStatus为SIGNAL
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
//注意unpark可以先于park调用
//前者颁发许可,后者消耗许可
//park()调用时会先检查许可,如果有则消耗许可却不会挂起
LockSupport.unpark(node.thread);
return true;
}
//移动被取消wait(中断标志)的节点
final boolean transferAfterCancelledWait(Node node) {
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node);
return true;
}
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
//释放资源
final int fullyRelease(Node node) {
boolean failed = true;
try {
//获取当前资源状态
int savedState = getState();
//独占式释放资源
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
public final boolean owns(ConditionObject condition) {
return condition.isOwnedBy(this);
}
//利用condition判断条件等待队列上是否有节点
public final boolean hasWaiters(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.hasWaiters();
}
//利用condition获取条件等待队列的长度
public final int getWaitQueueLength(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.getWaitQueueLength();
}
//利用condition获取条件等待队列上的线程
public final Collection getWaitingThreads(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.getWaitingThreads();
}
}
acquire部分:
实现了独占方式获取资源的逻辑。通过0/1来判断资源是否被占用,ReentrantLock实现了synchronized类似的功能,其子类Sync的lock()就是调用acquire(1)进行资源获取来代表显示的加锁操作。
acquire()会先调用子类扩展的tryAcquire()尝试获取资源,失败则addWaiter()创建新节点添加到同步队列尾部,并调用acquireQueued()使节点等待,这里的等待是先进行自旋然后调用park()阻塞。
具体的,acquireQueued()在两种情况下会停止自旋,这个节点就是队列中下一个可以获取资源的节点,那么直接获取资源并替换成为新的head,然后返回true。否则就只能够调用shouldParkAfterFailedAcquire()将节点移动到一个有效节点后面(waitStatus<0代表可以唤醒其后继),同时调用parkAndCheckInterrupt()利用park()将线程阻塞,等待被别人唤醒。
源码如下:
//尝试获取资源(独占方式)
//线程获取资源成功则直接返回,失败则阻塞并加入等待队列
public final void acquire(int arg) {
//首先当前线程tryAcquire()以独占方式尝试获取资源
//addWaiter()创建节点并加入等待队列,EXCLUSIVE标记为独占方式
//acquireQueued()使队列中这个节点等待
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//acquireQueued()返回true说明操作过程中标记了需要打断,在这里手动为线程打上中断标记
selfInterrupt();
}
//使节点进入等待状态(自旋/park阻塞)
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
//自旋
for (;;) {
//p记录传入节点的前趋
final Node p = node.predecessor();
//如果node的前趋是head,说明下一个就轮到自己了,则前趋删除出队,node成为新的head
//如果node的前趋不是head,但是node成功获取资源,那么旧head删除出队,node成为新的head
if (p == head && tryAcquire(arg)) {
//node成为新的head
setHead(node);
//setHead中将node的前趋置空,这一步将node前趋的next置空,实现双向断开
p.next = null;
failed = false;
return interrupted;
}
//shouldParkAfterFailedAcquire()把node放到一个可以通知自己的节点之后
//parkAndCheckInterrupt()让node绑定的线程阻塞
//两步结合防止线程永久park()
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
//线程按照上面逻辑正常阻塞,则记录中断标记,具体标记由外层的acquire()调用selfInterrupt()实现
interrupted = true;
}
} finally {
if (failed)
//failed只在自旋的第一个if分支中更新为false,走到这里说明自旋过程中无论如何也获取不到资源,则删除结点
cancelAcquire(node);
}
}
//将node放到一个可以通知自己的节点后面,确保绑定线程挂起后有人唤醒
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
//ws记录前趋的状态
int ws = pred.waitStatus;
//前趋状态为SIGNAL,那么前趋在释放资源之后会通知(唤醒)自己
if (ws == Node.SIGNAL)
//在资源被释放后,会有人通知自己,返回true表示绑定线程可以进入挂起状态
return true;
//ws为1(与前趋绑定的线程已经取消)那么前趋不能通知自己
if (ws > 0) {
do {
//一直向前找一个可以通知自己的节点(第一个出现的waitStatus小于0的)
node.prev = pred = pred.prev;
}
while (pred.waitStatus > 0);
//找到目标节点之后将自己插入到那个节点的后面
pred.next = node;
} else {
//更新一下目标节点的waitStatus
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
//阻塞当前调用的线程
private final boolean parkAndCheckInterrupt() {
//park使线程挂起
LockSupport.park(this);
//并设置被挂起线程的中断标志
return Thread.interrupted();
}
//AQS支持中断线程,下面两个方法就是上面的可中断版本
public final void acquireInterruptibly(int arg) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
private void doAcquireInterruptibly(int arg) throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
//直接抛出异常
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
//支持超时时间的acquire省略
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
//...
}
private boolean doAcquireNanos(int arg, long nanosTimeout)
//...
}
acquireShared部分:
实现了共享方式获取资源的逻辑。用stats=n来表示资源剩余量。比如CountDownLatch允许多个线程相互等待其他线程执行完毕这样可以让多个线程分块执行一个大任务,分别执行完之后在综合其结果。CountDownLatch(2)构造时,设置AQS的stats=2,线程1执行完任务a后调用countDown()等待,线程2执行完任务b后调用countDown()等待,而main线程中进行两个结果的综合所以调用await(),当countDown()次数等于2时,才会执行await()后面的代码。他的countDown()方法就是调用了releaseShared(1)共享方式释放资源,await()方法就是调用了acquireSharedInterruptibly(1)共享方式获取资源。
acquireShared()会先调用子类扩展的tryAcquireShared尝试获取资源,失败则doAcquireShared()创建新节点添加到同步队列尾部,并使节点等待,这里的等待是先进行自旋然后调用park()阻塞。
具体的,doAcquireShared()在一种情况下会停止自旋,这个节点就是队列中下一个可以获取资源的节点,那么调用setHeadAndPropagate()替换节点为新head,并唤醒后续节点,唤醒方式是调用doReleaseShared(),最后返回true停止自旋。否则就只能够调用shouldParkAfterFailedAcquire()将节点移动到一个有效节点后面(waitStatus<0代表可以唤醒其后继),同时调用parkAndCheckInterrupt()利用park()将线程阻塞,等待被别人唤醒。
源码如下:
//获取资源(共享方式)
public final void acquireShared(int arg) {
//调用tryAcquireShared()共享方式获取资源,失败返回负数,成功后返回剩余资源数
if (tryAcquireShared(arg) < 0)
//失败则doAcquireShared()
doAcquireShared(arg);
}
//使节点等待
private void doAcquireShared(int arg) {
//创建节点,绑定线程,标记共享
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
//节点自旋
for (;;) {
//获取前趋
final Node p = node.predecessor();
//自旋过程中,某一时刻前趋为head,那么下一个就轮到自己了,需要删除旧head,自己成为新head
if (p == head) {
//尝试获取资源
int r = tryAcquireShared(arg);
//大于0说明获取成功,且还剩余资源
if (r >= 0) {
//node设置为新head,唤醒后续节点
setHeadAndPropagate(node, r);
p.next = null;
//同样如果是被标记中断,则手动为线程打上中断标记
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
//shouldParkAfterFailedAcquire()移动节点
//parkAndCheckInterrupt()调用park()阻塞节点
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
//设置新head
//node是需要设置为head的节点,propagate是剩余资源数量
//这里是一次唤醒后续节点
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head;
//设置新head
setHead(node);
//还剩余资源,则
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
//s记录node的后继
Node s = node.next;
if (s == null || s.isShared())
//唤醒,这个方法会向后传播
doReleaseShared();
}
}
//上面方法的支持中断的版本
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null;
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
//指定超时时间的版本
private boolean doAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
//..
}
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
//..
}
release部分:
实现了独占方式释放资源的逻辑。先调用子类实现的tryRelease(),如果子类允许成功,那么AQS调用unparkSuccessor()利用park()取消后继节点的线程的挂起状态。当然这里仅仅是使线程活跃,但是真正获取资源拿到锁(可以比喻为有资格去跑任务)还是在acquireQueued()中的自旋逻辑中。
源码如下:
//释放资源
public final boolean release(int arg) {
//尝试释放资源(独占方式)
//队列中head独占资源,其他节点都阻塞,这里head释放资源后唤醒其后继
if (tryRelease(arg)) {
Node h = head;
//waitStatus在资源全部释放情况下为0
if (h != null && h.waitStatus != 0)
//唤醒head后继绑定的线程
unparkSuccessor(h);
return true;
}
return false;
}
//唤醒node的后继结点
private void unparkSuccessor(Node node) {
//检查一下node的waitStatus是否允许唤醒后继
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
//s记录node的后继
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
//调用unpark()唤醒挂起线程
LockSupport.unpark(s.thread);
}
releaseShared部分:
实现了共享方式释放资源的逻辑。同样是先调用子类的tryReleaseShared(),子类返回成功则doRelwaseShared()唤醒同步队列中节点,且共享方式允许传播。
源码如下:
//释放资源
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
//下面是真正的共享方式释放资源
doReleaseShared();
return true;
}
return false;
}
//共享方式释放资源
private void doReleaseShared() {
//自旋
for (;;) {
//因为head的后继就是下一个可以获取资源的节点,每次循环head都不一样,这里直接操作head
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
//如果head是SIGNAL状态
if (ws == Node.SIGNAL) {
//先尝试重置head的状态为0
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue;
//唤醒后继节点
unparkSuccessor(h);
}
//如果head的状态为0,则在重置为PROPAGATE确保能够传播唤醒操作
else if (ws == 0 &&!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue;
}
//如果此时head变了,其他节点成为新的head,说明当前节点不再持有资源,直接退出即可
if (h == head)
break;
}
}
CountDownLatch实现了一个闭锁,计数值由构造器传入,线程调用await会阻塞在门外面,调用countDown会减少一道门闩(也就是计数器),当门闩减到0表示可以开门,所有await阻塞的线程可以继续向下执行。下面分析其源码。
类申明,使用内部类实现了一个AQS。前面说了AQS自己实现了同步队列的维护包括节点绑定线程的阻塞、唤醒等等。然后具体资源的加减或0/1赋值由子类调用CAS来控制。
AQS要求子类tryAcquireShared()返回负数才能调用doAcquireShared()将线程加入同步队列进行挂起,所以这里的实现是判断资源剩余量,如果资源还有剩余说明countDown()调用次数还不够,调用await的仍然需要继续阻塞。
AQS要求子类tryReleaseShared()返回true才能调用doRelwaseShared()连续唤醒同步队列上的节点,所以这里的实现是资源开始不为0,但是经过本次减1操作变为0,说明countDown()调用次数够了,调用await()的线程可以全部被唤醒。
源码如下:
public class CountDownLatch {
//AQS
private final Sync sync;
//Sync实现了一个AQS
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
//指定AQS资源个数
Sync(int count) {
setState(count);
}
//获取资源个数
int getCount() {
return getState();
}
//尝试获取资源(共享):这里仅判断资源数量,资源为0返回1(成功),资源不为0返回-1(失败)
//await()会调用,用于在资源不为0时返回-1,然后由AQS调用doAcquireShared()创建节点加入同步队列进行挂起
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
//尝试释放资源(共享):这里仅判断资源数量,资源为0返回false(失败),资源不为0且减一成功之后变成0返回true(成功)
//countDown()会调用,用于在资源减1直到0时返回true,然后由AQS调用doRelwaseShared()唤醒队列节点
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
//构造器,初始化资源总量
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
//返回计数值
public long getCount() {
//返回AQS资源剩余量
return sync.getCount();
}
}
方法await()可以在资源不为0的情况下,让调用他的线程全部挂起。具体的是调用AQS的acquireShared()的过程,先调用Sync实现的tryAcquireShared(),如果资源不为0返回负数,则AQS调用doAcquireShared()将线程加入同步队列进行挂起。源码如下:
//等待计数值减到0
public void await() throws InterruptedException {
//AQS的acquireShared()会先调用子类扩展的tryAcquireShared()尝试获取资源,这里Sync的实现是判断资源是否为0,资源不为0表示失败
//失败则doAcquireShared()创建新节点添加到同步队列尾部,并使节点等待
sync.acquireSharedInterruptibly(1);
}
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
方法countDown()可以在资源减到0的情况下,唤醒所有被挂起的线程。具体的是调用AQS的releaseShared()的过程,先调用tryReleaseShared()将资源利用CAS减1,在减到0时返回true,则AQS调用doRelwaseShared()连续唤醒同步队列的的节点。源码如下:
//计数值减1
public void countDown() {
//AQS的releaseShared()会先调用子类扩展的tryReleaseShared()尝试释放资,这里Sync的实现是判断资源不为0,且减一成功,且最后变为0,则返回true表示成功
//子类返回成功则doRelwaseShared()唤醒同步队列中节点,且共享方式允许传播。
sync.releaseShared(1);
}
Semaphore提供了一种基于许可的同步方式,构造时初始化一个许可数量n,acquire()阻塞方式获取1个许可,release()返回1个许可,这样可以控制两个方法之间的任务代码只能最多有n个持有许可的线程同时执行,其余线程绑定节点后在同步队列上挂起等待。
与ReentrantLock类似,Lock()上锁,Unlock()释放锁,使用的是AQS的独占模式,而Semaphore使用的是AQS的共享模式。
类申明、Synv内部类申明源码如下:
public class Semaphore implements java.io.Serializable {
//Sync,原封不动的将AQS的state资源翻译成许可
abstract static class Sync extends AbstractQueuedSynchronizer {
//初始化state资源
Sync(int permits) {
setState(permits);
}
//尝试获取资源(非公平、共享)
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
//调用CAS更新资源,返回剩余量,多线程并发大家都是自旋调用CAS谁成功看运气与请求资源先后顺序无关
if (remaining < 0 ||compareAndSetState(available, remaining))
return remaining;
}
}
//尝试释放资源(共享)
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
//调用CAS更新资源,返回成功(后续由AQS连续唤醒节点)
if (compareAndSetState(current, next))
return true;
}
}
//获取许可剩余量
final int getPermits() {
//就是资源剩余量
return getState();
}
//减少许可数量
final void reducePermits(int reductions) {
for (;;) {
int current = getState();
int next = current - reductions;
if (next > current) // underflow
throw new Error("Permit count underflow");
//同样调用CAS更新资源
if (compareAndSetState(current, next))
return;
}
}
//清空许可
final int drainPermits() {
for (;;) {
int current = getState();
//调用CAS更新资源为0,返回更新前的值
if (current == 0 || compareAndSetState(current, 0))
return current;
}
}
}
//非公平Sync
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
//尝试获取资源(共享)
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
//公平Sync
static final class FairSync extends Sync {
private static final long serialVersionUID = 2014338818796000944L;
FairSync(int permits) {
super(permits);
}
//尝试获取资源(共享)
protected int tryAcquireShared(int acquires) {
for (;;) {
//通过判断"当前线程"是不是在CLH队列的队首节点绑定的线程,不是则说明自己不是等待最久的线程返回true
//直接返回-1,然后由AQS调用doAcquireShared()创建节点加入同步队列进行挂起
if (hasQueuedPredecessors())
return -1;
//如果当前线程是队首节点绑定的线程,说明自己是等待最久的那一个
//调用CAS更新资源
int available = getState();
int remaining = available - acquires;
if (remaining < 0 || compareAndSetState(available, remaining))
return remaining;
}
}
}
//AQS子类
private final Sync sync;
//构造器,默认非公平,最终拿到许可跑任务的线程不一定是先请求资源的,也可以指定是否公平
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
}
值得注意的是申明了公平、非公平两种AQS子类,我们知道资源的加减由子类在扩展方法中实现,根据CAS的调用结果返回整数或者布尔值,AQS只根据子类那四个扩展方法的返回值来判断是否需要加入同步队列挂起(负数)或者是否需要唤醒同步队列的节点(true)。
而资源核心操作就是子类调用CAS尝试修改资源数量,非公平模式下新来的节点直接尝试CAS修改资源,如果成功则返回资源剩余量,如果失败(仅仅在没有资源时会退出自旋而失败)则返回-1由AQS加入同步队列,多线程并发时大家都是自旋调用CAS来修改资源,谁成功看运气。
公平模式下会先调用AQS的hasQueuedPredecessors()判断是否有比自己等待更久的线程,判断方式是看当前线程是不是head.next(这个节点是下一个能获取资源的节点)所绑定的线程,如果不是则直接返回-1再由AQS将节点加入同步队列挂起,之后按照队列先后顺序唤醒节点然后再让他们尝试调用CAS修改资源。
接下来是获取许可,会先尝试获取资源,即先调用tryAcquireShared()利用自旋CAS修改资源,修改成功则直接退出返回正数,否则一直尝试修改,在资源剩余0时也会退出自旋返回-1,由AQS加入同步队列挂起。源码如下:
//获取许可
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);//支持中断
}
//获取许可
public void acquireUninterruptibly() {
sync.acquireShared(1);//不支持中断
}
//获取多个许可
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);//支持中断
}
//获取多个许可
public void acquireUninterruptibly(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireShared(permits);//不支持中断
}
//释放许可
public void release() {
sync.releaseShared(1);
}
//释放多个许可
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
//下面的尝试获取许可一系列操作是直接调用了子类扩展的nonfairTryAcquireShared直接自旋CAS尝试修改资源,成功返回true表示获取成功,如果资源为0时会获取失败返回false表示失败,暂时不明白为什么要给客户端导出这样的公有方法
public boolean tryAcquire() {
return sync.nonfairTryAcquireShared(1) >= 0;
}
public boolean tryAcquire(int permits) {
if (permits < 0) throw new IllegalArgumentException();
return sync.nonfairTryAcquireShared(permits) >= 0;
}
public boolean tryAcquire(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
}
其他剩余方法,源码如下:
//返回可用许可数
public int availablePermits() {
return sync.getPermits();
}
//清空剩余许可
public int drainPermits() {
return sync.drainPermits();
}
//减少一个许可
protected void reducePermits(int reduction) {
if (reduction < 0) throw new IllegalArgumentException();
sync.reducePermits(reduction);
}
//判断是否公平
public boolean isFair() {
return sync instanceof FairSync;
}
//判断当前线程是否是同步队列上的等待线程
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
//返回同步队列长度,这里是貌似是返回没有拿到许可的线程数量
public final int getQueueLength() {
return sync.getQueueLength();
}
//返回同步队列上的线程
protected Collection getQueuedThreads() {
return sync.getQueuedThreads();
}
ReentrantLock可以说实现了synchronized的一个替代,即独占锁、重入锁,使用AQS的独占模式实现,同时还支持Condition基于条件的线程通信,同样支持公平和非公平方式。
类申明如下,包括AQS的子类Sync,以及Sync的两个子类分别实现公平和非公平方式。资源state=0表示目前未被占用,state=n表示资源被某个线程占用且重入次数为n。另一方面非公平模式下AQS子类tryAcquire()会直接尝试CAS修改资源,也就是说lock()调用acquire()是公平的,因为大家都会尝试CAS而没有先后顺序。而公平模式下的tryAcquire()会先调用hasQueuedPredecessors()判断当前线程是否是队列第一个线程(这个线程等得最久),如果是才允许调用CAS修改资源否则加入队列。源码如下:
public class ReentrantLock implements Lock, java.io.Serializable {
//AQS子类,默认非公平
private final Sync sync;
//Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
//上锁,分别有公平和非公平两个方式,由子类实现
abstract void lock();
//尝试获取资源(非公平方式直接调用CAS修改资源,而不检查是否有比当前线程等待更久的线程)
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//state为0表示未被占用,为n表示被占用后的重入次数
int c = getState();
//可重入锁,使用acquires来记录重入的次数
//state=0说明资源还未被别人占用,则将资源数修改为acquires,并直接返回true
if (c == 0) {
if (compareAndSetState(0, acquires)) {
//设置独占资源的线程为当前线程
setExclusiveOwnerThread(current);
return true;
}
}
//如果当前线程是占有资源的节点绑定的线程,那么重入记录再加1
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//当前线程想要获取锁成功只有两种情况:
//1.刚开始资源为0说明资源未被独占,如果CAS修改成功则获取锁成功
//2.刚开始资源不为0说明资源被独占,但是独占资源的节点绑定的线程就是当前线程那么代表重入,如果CAS修改成功则重入
//其他情况均返回false,由AQS创建新节点加入同步队列加入自旋和挂起
return false;
}
//尝试释放资源(直接调用CAS修改资源)
protected final boolean tryRelease(int releases) {
//资源减
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//资源减到0表明未被任何节点独占
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();
}
//返回独占资源的线程
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
//返回被重入记录
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
//返回是否上锁
final boolean isLocked() {
return getState() != 0;
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0);
}
}
//Sync,非公平
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
//上锁,这里由于调用了AQS的acquire会阻塞一直到成功
final void lock() {
//CAS修改成功则设置当前线程为独占资源的线程
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
//尝试失败则调用AQS的acquire,后续会根据tryAcquire返回的false新建节点加入同步队列阻塞
else
acquire(1);
}
//尝试上锁,这里不涉及AQS的后续操作,只是一次CAS的尝试所以失败直接返回,不会加到同步队列
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
//Sync,公平
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
//上锁,这里由于调用了AQS的acquire会阻塞一直到成功
final void lock() {
//后续会根据tryAcquire返回的false新建节点加入同步队列阻塞
acquire(1);
}
//尝试上锁,同样不涉及AQS的后续操作,失败不会阻塞
//这里由于保证公平,所以使用hasQueuedPredecessors判断是否有比自己等待更长的线程,如果有则禁止立即调用CAS修改资源
//acquire会调用此方法,如果hasQueuedPredecessors表明自己不是等待最久的,需要由AQS加入同步队列
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;
}
}
//构造器,默认初始化非公平Sync
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
}
上锁客户端导出方法,这里就可以知道使用ReentrantLock上锁时,有的方法失败直接返回false,有的方法失败会阻塞,有的方法失败会阻塞但是支持中断。这是因为lock()尝试获取资源失败会由AQS加入同步队列所以会阻塞直到成功,tryLock()仅仅调用了子类的nonfairTryAcquire()并不会由AQS进行后续操作所以失败直接返回,而lockInterruptibly()调用了acquireInterruptibly()这个方法是AQS父类实现的即涉及同步队列操作又涉及中断操作,源码如下:
//客户端导出方法
//上锁(涉及到AQS的后续操作,会阻塞直到成功)
public void lock() {
sync.lock();
}
//上锁,支持中断(涉及到AQS的后续操作,会阻塞直到成功)
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
//上锁(不涉及到AQS的后续操作,失败直接返回)
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
//上锁(涉及到AQS的后续操作,失败会阻塞一定时间)
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
解锁客户端导出方法。源码如下:
//解锁
public void unlock() {
sync.release(1);
}
剩余一些其他方法,重点是condition的支持使用newCondition()返回一个条件对象,其维护了一个条件等待队列实现线程的await()失去竞争资源,signal()唤醒重获竞争资格。源码如下:
//条件对象,维护了条件等待队列(保存被await()的节点,也就是失去竞争资格的节点)
public Condition newCondition() {
return sync.newCondition();
}
//返回重入记录
public int getHoldCount() {
return sync.getHoldCount();
}
//返回资源是否被占用
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
//返回是否上锁
public boolean isLocked() {
return sync.isLocked();
}
//返回是否公平
public final boolean isFair() {
return sync instanceof FairSync;
}
//返回独占资源的线程
protected Thread getOwner() {
return sync.getOwner();
}
//返回是否有获取资源失败而在同步队列上阻塞的线程
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
//返回指定线程绑定的节点是否在同步队列上
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
//返回同步队列长度
public final int getQueueLength() {
return sync.getQueueLength();
}
//返回在同步队列上阻塞的所有线程
protected Collection getQueuedThreads() {
return sync.getQueuedThreads();
}
//返回条件等待队列上是否有节点(也就是判断指定条件对象上是否有调用await()而失去竞争资格的线程)
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//返回条件等待队列上的长度(也就是判断指定条件对象上调用await()而失去竞争资格的线程的个数)
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//返回条件等待队列上的所有线程
protected Collection getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
ReentrantReadWriteLock实现了一个读共享、写独占的读写锁,以优化ReentrantLock的同步效率。也就是说读锁共享且可重入,写锁互斥且可重入,写锁只能在没有任何锁被占用的情况下才能申请成功,而读锁只能在没有写锁被占用的情况下才能申请成功。
使用内部类Sync继承AQS,并扩展了两个子类NonfairSync、FairSync实现公平与非公平模式下的线程同步处理,本质上是混用AQS的独占、共享模式实现的。使用state的高16为记录读锁被占用的线程数,使用低16为来记录写锁被同一个线程的重入次数,这里使用state(R:0,W:0)来表示,前面说到AQS只负责节点入队或者唤醒,而子类Sync负责资源state的CAS修改,CAS尝试修改失败或者判断该线程不符合持锁规则需要交给AQS加入同步队列,这里Sync的两个子类NonfairSync、FairSync在调用CAS修改资源前检查节点是否符合公平性规则。同时使用两个内部类ReadLock、WriterLock实现了Lock接口以导出公有的上锁和解锁的客户端方法,也就是说相关的方法都委托Sync、NonfairSync、FairSync来实现。
读写锁规则:
1.如果当前线程获取write锁,当前线程也可以获取read锁,即锁降级
2.如果当前线程获取write锁,其他线程不能获取任何锁
3.如果当前线程获取read锁.其他线程也可以获取read锁
大概说一下锁流程:
首先state(R:0,W:0)
线程A申请read锁,使得state(R:1,W:0)
线程B申请read锁,使得state(R:2,W:0)
线程C申请write锁,由于state(R:2,W:0),获取失败,线程C加入同步队列
线程D申请read锁,虽然现在是read锁占有阶段,但由于同步队列中有等待中的C,线程D加入同步队列
线程A、B均释放read锁,使得state(R:0,W:0),会按顺序唤醒同步队列
线程C被唤醒,获取write锁,使得state(R:0,W:1)
线程C可锁降级,获取read锁,使得state(R:1,W:1)
在write锁被占有阶段,C之外的其他线程不能获取任何锁,均需要加入同步队列
关于公平与非公平:
Sync有两个空方法writerShouldBlock()、readerShouldBlock()交给子类实现,将公平性判断交给子类。只有返回false才允许后续调用CAS修改state。
NonfairSync(非公平):写锁writerShouldBlock()直接返回false让当前线程和刚刚从队列上唤醒的线程去竞争,这个刚刚被唤醒的线程可以是请求读锁、写锁的线程。读锁readerShouldBlock()在同步队列第一个节点(head的后继)是共享节点,也就是说即将被唤醒的节点是请求读锁的节点情况下返回false让当前线程和刚刚从队列上唤醒的线程去竞争,这个刚唤醒的线程必须是请求读锁的线程。这里的竞争就是各自调用CAS修改资源谁成功看运气,使得成功与否与请求顺序无关。
FairSync(公平):写锁writerShouldBlock()、读锁readerShouldBlock()均先判断当前线程是否是队列第一个节点绑定的线程(此线程等得最久)。如果不是则返回true后续由AQS加入同步队列。这样只能按照队列顺序挨个唤醒去竞争。
源码划分为下面几个部分:
1.Sync部分:是读写锁的核心,实现了独占、共享方式的state修改,将state高16记录占用读锁的线程数,低16为记录独占写锁重入次数。
2.NonfairSync、FairSync部分:分别实现了非公平、公平性过滤,AQS在调用CAS修改state前会先检查公平性。
3.ReadLock、WriteLock部分:调用Sync、NonfairSync、FairSync导出一系列公有的客户端方法。
4.ReentrantReadWriteLock部分:使用上面5个内部类合起来完成读写锁。
Sync部分:
(1)Sync使用state来记录占用读锁的线程数和独占写锁时的重入次数。
(2)readerShouldBlock()、writerShouldBlock()交给子类实现以判断是否公平是否需要禁止修改state。
(3)tryAcquire()尝试获取资源(独占),是交给写锁用的,所以如果已经占有写锁直接set更新重入计数,如果当前无任何锁则尝试占用写锁即调用CAS修改state,如果当前是读锁阶段,或者由子类判断当前线程需要阻塞,这两种情况会返回false由AQS添加到同步队列中。
(4)tryRelease()尝试释放资源(独占),是交给写锁用的,这里调用CAS更新写锁重入记录。
(5)tryAcquireShared()尝试获取资源(共享),这是给读锁用的,写锁占用节点直接返回失败由AQS添加到队列,只要不是写锁占用阶段都可以尝试获取读锁即调用CAS增加占用读锁的线程数,返回负数会由AQS添加到同步队列。
(6)tryReleaseShared()尝试释放资源(共享)。
(7)tryWriteLock()尝试上write锁,和tryAcquireShared区别在于,前者仅做一次CAS尝试,不涉及队列操作,所以立即返回结果,后者在AQS一系列调用链上,涉及队列操作,所以失败会添加到队列上阻塞直到成功。
(8)tryReadLock()尝试上read锁,前者仅做一次CAS尝试,不涉及队列操作,所以立即返回结果,后者在AQS一系列调用链上,涉及队列操作,所以失败会添加到队列上阻塞直到成功。
源码如下:
//Sync内部类
abstract static class Sync extends AbstractQueuedSynchronizer {
//资源state是一个32为的int类型,由于读锁共享且可重入、写锁互斥且可重入,所以需要记录读锁被占有的线程数量,需要记录写锁被一个线程占有的重入次数
//高16位用来表示读锁占有的线程数量,低16位表示写锁被同一个线程重入的次数,可以通过位移运算读出这两个值
static final int SHARED_SHIFT = 16;//常量
static final int SHARED_UNIT = (1 << SHARED_SHIFT);//读锁加1,这里高16位
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;//锁被持有次数最大为65535
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;//写锁掩码,用于得出低16位
//读锁计数,当前持有读锁的线程数,这里返回高16位
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
//写锁计数,当前写锁重入的次数,这里返回低16位
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
//内部类HoldCounter,记录当前线程对读锁的重入次数,也可以说当前线程占用的读锁数量,每个线程均有一个此变量,他们的总和就是占用读锁的线程总数
static final class HoldCounter {
//获取读锁重入记录
int count = 0;
//线程id
final long tid = getThreadId(Thread.currentThread());
}
//缓存的是上一个(最近)获取读锁的线程
private transient HoldCounter cachedHoldCounter;
//内部类ThreadLocalHoldCounter,使用线程本地变量保存HoldCounter信息
static final class ThreadLocalHoldCounter extends ThreadLocal {
public HoldCounter initialValue() {
//在没有set的情况下直接返回新HoldCounter
return new HoldCounter();
}
}
private transient ThreadLocalHoldCounter readHolds;
//最近一个获取读锁成功、且还没释放的线程(tryAcquireShared()可以看到他的赋值过程)
private transient Thread firstReader = null;
//记录firstReader的读锁重入次数,由于在tryAcquireShared()中每次都将firstReader赋值为当前线程,所有这个值实际上记录了当前线程读锁的重入次数
private transient int firstReaderHoldCount;
//构造器,初始化state
Sync() {
readHolds = new ThreadLocalHoldCounter();
setState(getState());
}
//读写是否需要阻塞,交给两个子类实现,用于实现公平和非公平
abstract boolean readerShouldBlock();
abstract boolean writerShouldBlock();
//尝试获取资源(独占)
//是交给写锁用的,所以如果已经占有写锁直接set更新重入计数,如果当前无任何锁则尝试占用写锁即调用CAS修改state
//如果当前是读锁阶段,或者由子类判断当前线程需要阻塞,这两种情况会返回false由AQS添加到同步队列中
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);//写锁重入次数
//state!=0说明当前存在锁被占用,具体是写占用还是读占用这里还不清楚
if (c != 0) {
//写锁重入为0,说明当前是读锁占用阶段,且当前线程没有占用读锁
if (w == 0 || current != getExclusiveOwnerThread())
return false;
//写锁重入不为0,但是溢出
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//写重入不为0,说明当前是写锁占用阶段
//更新重入计数,注意写锁占用阶段不可能存在其他线程尝试对任何锁的获取,所以这里不用CAS也是线程安全的
setState(c + acquires);
return true;
}
//上面分支未返回的话,走到这里说明当前没有任何锁被占用,所以直接调用CAS修改state
if (writerShouldBlock() || !compareAndSetState(c, c + acquires))
return false;
//上一步CAS成功修改了state,且未返回,说明本次写锁获取成功,修改当前线程为独占锁的线程
setExclusiveOwnerThread(current);
//然后返回true跳过AQS的后续操作,如果上面任何一步返回false则会有AQS创建节点添加到同步队列
return true;
}
//尝试释放资源(独占)
//是交给写锁用的,这里调用CAS更新写锁重入记录
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//写锁重入数减少
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
//如果写锁重入记录减到0,那么记录占用读锁的线程的引用置空
if (free)
setExclusiveOwnerThread(null);
//更新写锁重入记录
setState(nextc);
//false:本次释放成功,但是重入记录还没减到0,当前仍然处于写锁占用阶段,跳过AQS的后续操作
//true:本次释放成功,重入记录减到0,当前没有任何锁被占用,由AQS唤醒队列后续节点
return free;
}
//尝试获取资源(共享)
//这是给读锁用的,写锁占用节点直接返回失败由AQS添加到队列,只要不是写锁占用阶段都可以尝试获取读锁即调用CAS增加占用读锁的线程数
//返回负数会由AQS添加到同步队列
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
//写锁重入不为0,且不是当前线程占用写锁
if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current)
//同样返回负数由AQS添加到同步队列中
return -1;
int r = sharedCount(c);
//上个分支未返回,说明当前不是写锁占用阶段,那么可以尝试获取读锁,直接调用CAS修改state
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//下面的逻辑主要是更新firstReader和firstReaderHoldCount
//占用读锁的线程数从0变为1
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
}
else if (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
//返回1跳过AQS后续操作
return 1;
}
//上面分支可以理解为一个快速的尝试(即调用一次CAS),如果未返回则调用fullTryAcquireShared
return fullTryAcquireShared(current);
}
//尝试获取资源(共享)
//自旋过程中只有三种情况退出并返回
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
//自旋
for (;;) {
int c = getState();
//情况1:写锁不为0,且当前线程不是独占写锁的线程,则返回-1
if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current)
return -1;
}
//情况2:如果子类判断此处申请读锁的线程需要阻塞,且
else if (readerShouldBlock()) {
if (firstReader == current) {
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
}
}
if (rh.count == 0)
return -1;
}
}
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//情况3:CAS尝试修改state成功
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (sharedCount(c) == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
cachedHoldCounter = rh;
}
return 1;
}
}
}
//尝试释放资源(共享)
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
//firstReader置空,firstReaderHoldCount减1
if (firstReader == current) {
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
//自旋
for (;;) {
int c = getState();
//读锁占用线程数减1
int nextc = c - SHARED_UNIT;
//CAS更新占用读锁的线程数
if (compareAndSetState(c, nextc))
//仅仅读锁全部释放才返回true
//因为读锁占用阶段,同步队列的第一个节点一定是请求写锁的节点,因为新来的请求读锁的节点可以直接请求成功而不会添加到队列上,还没减到0就返回true唤醒一个请求写锁的线程没有意义
return nextc == 0;
}
}
//尝试上write锁,和tryAcquireShared区别在于
//前者仅做一次CAS尝试,不涉及队列操作,所以立即返回结果
//后者在AQS一系列调用链上,涉及队列操作,所以失败会添加到队列上阻塞直到成功
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
int c = getState();
if (c != 0) {
int w = exclusiveCount(c);
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
if (!compareAndSetState(c, c + 1))
return false;
setExclusiveOwnerThread(current);
return true;
}
//尝试上read锁
//前者仅做一次CAS尝试,不涉及队列操作,所以立即返回结果
//后者在AQS一系列调用链上,涉及队列操作,所以失败会添加到队列上阻塞直到成功
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
int c = getState();
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return false;
int r = sharedCount(c);
if (r == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return true;
}
}
}
//判断当前线程是否占有写锁
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
private IllegalMonitorStateException unmatchedUnlockException() {
return new IllegalMonitorStateException(
"attempt to unlock read lock, not locked by current thread");
}
//返回条件对象,由于只用于独占模式,所有在这里只有写锁可以返回condition对象
final ConditionObject newCondition() {
return new ConditionObject();
}
//返回独占写锁的线程
final Thread getOwner() {
return ((exclusiveCount(getState()) == 0) ?
null :
getExclusiveOwnerThread());
}
//返回占用 读锁的线程个数
final int getReadLockCount() {
return sharedCount(getState());
}
//返回是否写锁被占用
final boolean isWriteLocked() {
return exclusiveCount(getState()) != 0;
}
//返回写锁重入计数
final int getWriteHoldCount() {
return isHeldExclusively() ? exclusiveCount(getState()) : 0;
}
//返回
final int getReadHoldCount() {
if (getReadLockCount() == 0)
return 0;
Thread current = Thread.currentThread();
if (firstReader == current)
return firstReaderHoldCount;
HoldCounter rh = cachedHoldCounter;
if (rh != null && rh.tid == getThreadId(current))
return rh.count;
int count = readHolds.get().count;
if (count == 0) readHolds.remove();
return count;
}
final int getCount() { return getState(); }
}
NonfairSync、FairSync部分:
NonfairSync(非公平):写锁writerShouldBlock()直接返回false让当前线程和刚刚从队列上唤醒的线程去竞争,这个刚刚被唤醒的线程可以是请求读锁、写锁的线程。读锁readerShouldBlock()在同步队列第一个节点(head的后继)是共享节点,也就是说即将被唤醒的节点是请求读锁的节点情况下返回false让当前线程和刚刚从队列上唤醒的线程去竞争,这个刚唤醒的线程必须是请求读锁的线程。这里的竞争就是各自调用CAS修改资源谁成功看运气,使得成功与否与请求顺序无关。
FairSync(公平):写锁writerShouldBlock()、读锁readerShouldBlock()均先判断当前线程是否是队列第一个节点绑定的线程(此线程等得最久)。如果不是则返回true后续由AQS加入同步队列。这样只能按照队列顺序挨个唤醒去竞争。
源码如下:
//NonfairSync内部类
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
//写锁非公平
final boolean writerShouldBlock() {
//这里返回false让当前线程和刚刚从队列上唤醒的线程去竞争,这个刚刚被唤醒的线程可以是请求读锁、写锁的线程
return false;
}
//读锁非公平
final boolean readerShouldBlock() {
//方法在同步队列第一个节点(head的后继)是共享节点,也就是说即将被唤醒的节点是请求读锁的节点,的情况下返回false,
//这里返回false让当前线程和刚刚从队列上唤醒的线程去竞争,这个刚唤醒的线程必须是请求读锁的线程
return apparentlyFirstQueuedIsExclusive();
}
}
//FairSync内部类
//hasQueuedPredecessors()判断当前线程是否是队列第一个节点绑定的线程(此线程等得最久),如果不是则返回true后续由AQS加入同步队列
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
//写锁公平
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
//读锁公平
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
ReadLock、WriteLock部分:
调用上面三个类相关方法,导出公有的客户端方法。源码如下:
//ReadLock内部类
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync;
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
public void lock() {
sync.acquireShared(1);
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public boolean tryLock() {
return sync.tryReadLock();
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public void unlock() {
sync.releaseShared(1);
}
public Condition newCondition() {
throw new UnsupportedOperationException();
}
public String toString() {
int r = sync.getReadLockCount();
return super.toString() +
"[Read locks = " + r + "]";
}
}
//WriteLock内部类
public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync;
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
public void lock() {
sync.acquire(1);
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock( ) {
return sync.tryWriteLock();
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
public int getHoldCount() {
return sync.getWriteHoldCount();
}
}
ReentrantReadWriteLock部分:
剩下就是读写锁的基本成员。源码如下:
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
//读锁
private final ReentrantReadWriteLock.ReadLock readerLock;
//写锁
private final ReentrantReadWriteLock.WriteLock writerLock;
//AQS子类
final Sync sync
public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; }
//构造器,初始化,默认非公平
public ReentrantReadWriteLock() {
this(false);
}
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
//判断是否公平
public final boolean isFair() {
return sync instanceof FairSync;
}
//返回独占写锁的线程
protected Thread getOwner() {
return sync.getOwner();
}
//返回占用读锁的线程计数
public int getReadLockCount() {
return sync.getReadLockCount();
}
//返回写锁是否被占用
public boolean isWriteLocked() {
return sync.isWriteLocked();
}
//返回是否是当前线程占用写锁
public boolean isWriteLockedByCurrentThread() {
return sync.isHeldExclusively();
}
//返回写锁的重入次数
public int getWriteHoldCount() {
return sync.getWriteHoldCount();
}
//
public int getReadHoldCount() {
return sync.getReadHoldCount();
}
//返回队列上独占模式节点绑定的线程(也即是请求写锁的线程)
protected Collection getQueuedWriterThreads() {
return sync.getExclusiveQueuedThreads();
}
//返回队列上共享模式节点的线程(也即是请求读锁的线程)
protected Collection getQueuedReaderThreads() {
return sync.getSharedQueuedThreads();
}
//返回同步队列上是否有线程
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
//返回指定线程是否是同步队列上的线程
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
//返回同步队列长度
public final int getQueueLength() {
return sync.getQueueLength();
}
//返回同步队列上所有线程
protected Collection getQueuedThreads() {
return sync.getQueuedThreads();
}
//判断指定条件队列上是否有线程
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//返回指定条件队列的长度
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//返回指定条件队列的线程
protected Collection getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//CAS支持
private static final sun.misc.Unsafe UNSAFE;
private static final long TID_OFFSET;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class> tk = Thread.class;
TID_OFFSET = UNSAFE.objectFieldOffset
(tk.getDeclaredField("tid"));
} catch (Exception e) {
throw new Error(e);
}
}
//获取线程ID
static final long getThreadId(Thread thread) {
return UNSAFE.getLongVolatile(thread, TID_OFFSET);
}
}
看过Unsafe的源码,看AtomicInteger这一类源码就比较简单了。这一类首先使用value保存int值,使用volatile修饰保证线程可见性(即线程每次读取均从主内存读取,而不是读取线程自己的工作内存的副本值,这样可以确保某个线程将副本值覆盖主内存的写操作对其他线程的可见性)。自增这一类操作都是乐观方式的失败重试机制。乐观锁:自旋+CAS。
源码如下:
public class AtomicInteger extends Number implements java.io.Serializable {
//获取字段value在实例对象中的偏移量
static {
try {
valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
//字段value在对象中的偏移量
private static final long valueOffset;
//Unsafe支持
private static final Unsafe unsafe = Unsafe.getUnsafe();
//int值
private volatile int value;
//构造器
public AtomicInteger(int initialValue) {
value = initialValue;
}
public AtomicInteger() {
}
//getter、setter
public final int get() {
return value;
}
public final void set(int newValue) {
value = newValue;
}
//CAS
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}
//CAS+自旋
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
//CAS
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//CAS+自旋:修改前获取旧值,然后CAS时如果旧值没有被改变则修改成功,否则继续自旋直到某一次CAS成功则退出
//均调用Unsafe的getAndAddInt()
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
//同理下面也是自旋+CAS
//这里是新增的函数式编程,IntUnaryOperator接受一个参数同为类型int,返回值类型也为int
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return prev;
}
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
}
public final int getAndAccumulate(int x,IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return prev;
}
public final int accumulateAndGet(int x,IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return next;
}
//toString
public String toString() {
return Integer.toString(get());
}
//返回不同精度的值
public int intValue() {
return get();
}
public long longValue() {
return (long)get();
}
public float floatValue() {
return (float)get();
}
public double doubleValue() {
return (double)get();
}
}