AbstractQueuedSynchronizer简称AQS
AQS中获取或释放操作的规范式
boolean acquire()throws InterruptedException{
while(state does not permit acquire){
if(blocking acquisition requested){
enqueue current thread if not already queued
block current thread
}else{
return failure
}
}
possibly update synchronization state
dequeue thread if it was queued
return success
}
void release(){
update synchronization state
if(new state may permit a blocked thread to acqquire){
unblock one or more queued threads
}
}
支持独占获取的Synchronizer应该实现tryAcquire、tryRelease和isHeldExclusively这几个受保护的方法,而支持共享获取的Synchronizer应该实现tryAcquireShared和tryReleaseShared。
public class OneShotLatch{
private final Sync sync=ew Sync();
public void signal(){
sync.releaseShared(0);
}
public void await()throws InterruptedException{
sync.acquireSharedInterruptibly(0);
}
private class Sync extends AbstractQueuedSynchronizer{
protected int tryAcquitreShared(int ignored){
//如果闭锁打开则成功(state==1),否则失败
return (getState()==1)?1:-1;
}
protected boolean tryReleaseShared(itn ignored){
//闭锁现在已经打开
setState(1);
//现在,其他线程可以获得闭锁
return true;
}
}
}
上面的例子是使用 AQS 实现的二元闭锁。最初,闭锁是关闭的。任何调用 await 的线程都会阻塞,直到打开闭锁。一旦闭锁被一个 signal 调用打开,等待中的线程会被释放,而且随后到达闭锁的线程也被允许执行。
上面的例子还少一些有用的特性——比如限时的请求操作以及检查闭锁状态的能力。
juc中没有一个Synchronizer是直接扩展AQS的——相反,他们都委托了AQS的私有内部子类。
protected boolean tryAcquire(int ignored){
final Thread current=Thread.currentThread();
int c=getState();
if(c==0){
if(compareAndSetState(0,1)){
owner=current;
return true;
}
}else if(current==owner){
setState(c+1);
return true;
}
return false;
}
上面的例子是非公平的 ReentrantLock 中 tryAcquire 的实现
只有当前线程刚刚获取到锁或者刚刚释放了锁的时候,才会修改owner。
protected int tryAcquireShared(int acquires){
while(true){
int available=getState();
int remaining=available-acquires;
if(remaining<0||compareAndSetState(available,remaining)){
return remaining;
}
}
}
protected boolean tryReleaseShared(int releases){
while(true){
int p=getState();
if(compareAndSetState(p,p+releases)){
return true;
}
}
}
上面的例子是Semaphore的tryAcquireShared和tryReleaseShared方法
public class SimilatedCAS{
private int value;
public synchronized int get(){
return value;
}
public synchronized int compareAndSwap(int expectedValue,int newValue){
int oldValue=value;
if(oldValue==expectedValue){
value=newValue;
}
return oldValue;
}
public synchronized boolean compareAndSet(int expectedValue,int newValue){
return (expectedValue==(compareAndSwap(expectedValue,newValue)));
}
}
public class CasCounter{
private SimulatedCAS value;
public int getValue(){
return value.get();
}
public int increment(){
int v;
do{
v=value.get();
}while(v!=value.compareAndSwap(v,v+1));
return v+1;
}
}
public class CaseNumberRange{
private static class IntPair{
final int lower;
final int upper;
}
private final AtomicReference<IntPair> value=new AtomicReference<IntPair>(new IntPair(0,0));
public int getLower(){
return values.get().lower;
}
public int getUpper(){
return values.get().upper;
}
public void setLower(int i){
while(true){
IntPair oldv=values.get();
if(i>oldv.upper){
throw new IllegalArgumentException(“Can’t set lower to”+i+”>upper”);
}
IntPair newV=new IntPair(i,oldv,newv);
if(values.compareAndSet(oldv,newv)){
return;
}
}
}
//setUpper完全类似
}
public class ReentrantLockPseudoRandom extends PseudoRandom{
private final Lock lock=new ReentrantLock(false);
private int seed;
ReentrantLockPseudoRandom(int seed){
this.seed=seed;
}
public int nextInt(int n){
lock.lock();
try{
int s=seed;
seed=calculateNext(s);
int remainder=s%n;
return remainder>0?remainder:remainder+n;
}finally{
lock.unlock();
}
}
}
public class AtomicPseudoRandom extends PseudoRandom{
private AtomicInteger seed;
AtomicPseudoRandom(int seed){
this.seed=new AtomicInteger(seed);
}
public int nextInt(int n){
while(true){
int s=seed.get();
int nextSeed=calculateNext(s);
if(seed.compareAndSet(s,nextSeed)){
int remainder=s%n;
return remainder>0?remainder:remainder+n;
}
}
}
}
一个线程的失败或挂起不应该影响其他线程的失败或挂起,这样的算法被称为非阻塞算法。
如果算法的每一步骤中都有一些线程能够继续执行,那么这样的算法被称为锁自由算法。
public class ConcurrentStack<E>{
AtomicReference<Node<E>> top=new AtomicReference<Node<E>>();
public void push(E item){
Node<E> newHead=new Node<E>(item);
Node<E> oldHead;
do{
oldHead=top.get();
newHead.next=oldHead;
}while(!top.compareAndSet(oldHead,newHead));
}
public E pop(){
Node<E> oldHead;
Node<E> newHead;
do{
oldHead=top.get();
if(oldHead==null){
return null;
}
newHead=oldHead.next;
}while(!top.compareAndSet(oldHead,newHead));
return lodHead.item;
}
private static class Node<E>{
public final E item;
public Node<E> next;
public Node(E item){
this.item=item;
}
}
}
上面是使用 Treiber 算法的非阻塞栈
构建非阻塞算法的窍门是:缩小原子化的范围到唯一的变量。
public class LickedQueue<E>{
private static class Node<E>{
final E item;
final AtomicReference<Node<E>> next;
public Node(E item,Node<E> next){
this.item=item;
this.next=nwe AtomicReference<Node<E>>(next);
}
}
private final Node<E> dumy=new Node<E>(null,null);
private final AtomicReference<Node<E>> head=new AtomicReference<Node<E>>(dumy);
private final AtomicReference<Node<E>> tail=new AtomicReference<Node<E>>(dumy);
public boolean put(E item){
Node<E> newNode=new Node<E>(item,null);
while(true){
Node<E> curTail=tail.get();
Node<E> tailNext=curTail.next.get();
if(curTail==tail.get()){
if(tailNext!=null){
//队列处于静止状态,推进尾节点
tail.compareAndSet(curTail,tailNext);
}else{
//处于静止状态,尝试插入新节点
if(curTail.next.compareAndSet(null,newNode)){
//插入成功,尝试推进尾节点
tail.compareAndSet(curTail,newNode);
return true;
}
}
}
}
}
}
上面的例子是Michael-Scott非阻塞队列算法中的插入。
private class Node<E>{
private final E item;
private volatile Node<E> next;
public Node(E item){
this.item=item;
}
}
private static AtomicReferenceFieldUpdater<Node,Node> nextUpdater=AtomicReferenceFieldUpdater.newUpdater(Node.class,Node.class,”next”);
在 ConcurrentLinkedQueue 中,更新 Node 的 next 域是通过使用 nextUpdater 的 compareAndSet 方法实现的。