【Java并发】JAVA并发编程实战-读书笔记19

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应该实现tryAcquiretryReleaseisHeldExclusively这几个受保护的方法,而支持共享获取的Synchronizer应该实现tryAcquireSharedtryReleaseShared

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;

    }

  }

}

上面的例子是SemaphoretryAcquireSharedtryReleaseShared方法

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 方法实现的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值