CLH(Craig, Landin, and Hagersten)锁常用于实现自旋锁,AQS使用一种变形后的CLH锁队列,来代替阻塞同步。
1 | +------+ prev +-----+ +-----+ |
AQS使用双向队列,每一个Node都代表一个线程,有status属性,标记着线程是否应该被阻塞,prev指针指向前个节点,next指针(图中没有画出)指向后续节点,head和tail不言而喻
1 | /** AbstractQueuedSynchronizer#Node.java **/ |
接下来再看一下AQS定义的域,特别要注意这里的state
,表示同步状态,而不是上文中的线程等待状态waitStatus
。
AQS内部通过一个int类型的state字段表示同步状态,状态的具体含义可以子类来定义,例如ReentrantLock中用state表示线程重入的次数,Semaphore表示可用的许可的数量等。使用int是由于int能够应对大部分的场景,而long在很多平台需要使用额外锁来保证一致性的读取。(引用自他山之石)
1 | // 头节点,通过setHead方法修改,等待状态不能是CANCELLED |
AQS的一些包装UnSafe的CAS操作
1 | private static final Unsafe unsafe = Unsafe.getUnsafe(); |
【题外话】补充一下,因为UnSafe做了安全验证,只允许信任的JDK调用,如果使用如上所示的Unsafe.getUnsafe()
或者直接实例化,那么会抛Caused by: java.lang.SecurityException: Unsafe
的异常,可以通过反射其内部的theUnsafe
的域来进行实例化。
1 | Field f = Unsafe.class.getDeclaredField("theUnsafe"); //Internal reference |