对AQS进行解析后,先来实现两个简单的基于AQS的类,然后再解析juc里基于AQS构造的类。
1、基于AQS的类的示例
首先先看这个类,这个类是《Java并发编程实战》的一个示例,AQS源码的注释里也给了类似的实现。这个类是以共享模式实现的,在调用signal之前,调用await方法的线程都将被阻塞,main方法的示例演示了这种情况。
1 public class Latch { 2 private Sync sync = new Sync(); 3 4 private class Sync extends AbstractQueuedSynchronizer{ 5 @Override 6 protected int tryAcquireShared(int arg) {//重写tryAcquireShared方法 7 return getState() == 1 ? 1 : -1; 8 } 9 10 @Override 11 protected boolean tryReleaseShared(int arg) {//重写tryReleaseShared方法 12 setState(1); 13 return true; 14 } 15 } 16 17 public void signal(){//调用这个方法会调用releaseShared方法,会调用tryReleaseShared方法,将state设置为0 没调用这个方法之前调用tryAcquireShared的返回值都是0,线程会阻塞 18 sync.releaseShared(0); 19 } 20 21 public void await() throws InterruptedException {//调用这个方法会调用acquireSharedInterruptibly方法,会调用tryAcquireShared方法,如果返回值大于0,则集训运行;否则阻塞 22 sync.acquireSharedInterruptibly(0); 23 } 24 25 public static void main(String [] args) throws InterruptedException { 26 Latch latch = new Latch(); 27 Runnable runnable = new Runnable() { 28 @Override 29 public void run() { 30 try { 31 latch.await(); 32 } catch (InterruptedException e) { 33 e.printStackTrace(); 34 } 35 System.out.println("haha"); 36 } 37 }; 38 39 new Thread(runnable).start(); 40 new Thread(runnable).start(); 41 42 Thread.sleep(5 * 1000); 43 44 System.out.println("xixi"); 45 latch.signal(); 46 } 47 }
这个类是AQS注释里给出的一个实现的一部分。这个类是以独占模式实现的。同时只能有一个线程
1 public class Mock { 2 private Sync sync = new Sync(); 3 4 private class Sync extends AbstractQueuedSynchronizer{ 5 @Override 6 protected boolean isHeldExclusively() { 7 return getState() == 1; 8 } 9 10 @Override 11 protected boolean tryAcquire(int acquires) {//重写tryAcquire方法,用cas尝试将state从0置为1 12 assert acquires == 1; 13 if (compareAndSetState(0, 1)){ 14 setExclusiveOwnerThread(Thread.currentThread());//如果将state从0置为1成功,则将当前线程设置为独占模式持有资源的线程 15 return true; 16 } 17 return false; 18 } 19 20 @Override 21 protected boolean tryRelease(int releases) { 22 assert releases == 1; 23 if (getState() == 0){//如果state为0,则说明资源没有被占用,不需要释放 抛出一个异常 24 throw new IllegalMonitorStateException(); 25 } 26 setExclusiveOwnerThread(null);//将资源拥有者线程置为null 27 setState(0);//将state置为0,资源释放 28 return true; 29 } 30 } 31 32 @Test 33 public void lock(){ 34 sync.acquire(1); 35 } 36 37 public boolean tryAcquire(){ 38 return sync.tryAcquire(1); 39 } 40 41 public void unlock(){ 42 sync.release(1); 43 } 44 45 public static void main(String [] args) throws InterruptedException { 46 Mock mock = new Mock(); 47 Runnable runnable = new Runnable() { 48 @Override 49 public void run() { 50 mock.lock(); 51 System.out.println("haha"); 52 try { 53 Thread.sleep(5 * 1000); 54 } catch (InterruptedException e) { 55 e.printStackTrace(); 56 } 57 mock.unlock(); 58 } 59 }; 60 61 new Thread(runnable).start(); 62 new Thread(runnable).start(); 63 64 mock.lock(); 65 System.out.println("xixi"); 66 Thread.sleep(5 * 1000); 67 mock.unlock(); 68 } 69 }
2、juc里基于AQS构造的类
Semaphore类:
内部抽象类Sync:
1 abstract static class Sync extends AbstractQueuedSynchronizer { 2 private static final long serialVersionUID = 1192457210091910933L; 3 4 Sync(int permits) { 5 setState(permits); 6 } 7 8 final int getPermits() { 9 return getState(); 10 } 11 12 final int nonfairTryAcquireShared(int acquires) {//不公平尝试获取共享锁 13 for (;;) { 14 int available = getState(); 15 int remaining = available - acquires; 16 if (remaining < 0 || 17 compareAndSetState(available, remaining))//如果剩下的资源不够分配,直接返回,会进入阻塞状态;如果剩下的资源足够分配,自旋直到分配成功,返回分配后剩下的资源 18 return remaining; 19 } 20 } 21 22 protected final boolean tryReleaseShared(int releases) {//尝试释放锁 23 for (;;) {//自旋 24 int current = getState(); 25 int next = current + releases; 26 if (next < current)//next溢出为负数 抛出异常 27 throw new Error("Maximum permit count exceeded"); 28 if (compareAndSetState(current, next))//cas修改state 29 return true; 30 } 31 } 32 33 final void reducePermits(int reductions) {//减少许可 34 for (;;) { 35 int current = getState(); 36 int next = current - reductions; 37 if (next > current) // underflow 38 throw new Error("Permit count underflow"); 39 if (compareAndSetState(current, next)) 40 return; 41 } 42 } 43 44 final int drainPermits() {//将许可清空 45 for (;;) { 46 int current = getState(); 47 if (current == 0 || compareAndSetState(current, 0)) 48 return current; 49 } 50 } 51 }
内部类NonfairSync:
这个类继承自抽象类Sync,实现了tryAcquireShared方法,由类名可知这个类是非公平获取资源的(非公平就是说一个线程尝试获取资源时,就算有其它线程在排队获取资源,但是由于这些资源处于等待状态,会让新的线程先尝试获取资源,如果直接能获取就让新线程直接运行,不再进入等待队列排队;如果不能直接获取,就再进入阻塞队列。非公平可能减少线程阻塞唤醒的次数,性能要比公平好一些)。
在AQS里的acquireShared方法会先调用tryAcquireShared方法再根据结果决定是执行还是等待,这里tryAcquireShared的实现就可以让Semaphore有非公平的功能。
1 static final class NonfairSync extends Sync { 2 private static final long serialVersionUID = -2694183684443567898L; 3 4 NonfairSync(int permits) { 5 super(permits); 6 } 7 8 protected int tryAcquireShared(int acquires) { 9 return nonfairTryAcquireShared(acquires); 10 } 11 }
内部类FairSync:
上面说了非公平的版本,公平的版本和非公平的版本区别就在tryAcquireShared方法里面。在FairSync里,如果队列里有其它线程等待,就直接返回-1,新线程会直接放入队列中;如果没有其它线程等待才尝试获取资源。
1 static final class FairSync extends Sync { 2 private static final long serialVersionUID = 2014338818796000944L; 3 4 FairSync(int permits) { 5 super(permits); 6 } 7 8 protected int tryAcquireShared(int acquires) { 9 for (;;) { 10 if (hasQueuedPredecessors()) 11 return -1; 12 int available = getState(); 13 int remaining = available - acquires; 14 if (remaining < 0 || 15 compareAndSetState(available, remaining)) 16 return remaining; 17 } 18 } 19 }
Semaphore的构造函数:
Semaphore的构造函数有两个,都需要传许可(资源)数,另一个可以传是否公平,来决定资源分配的方式。
1 public Semaphore(int permits) { 2 sync = new NonfairSync(permits); 3 } 4 5 public Semaphore(int permits, boolean fair) { 6 sync = fair ? new FairSync(permits) : new NonfairSync(permits); 7 }
Semaphore的其它方法基本上都是调用Sync(AQS)的方法实现的,可以看AQS的解析或Semaphore抽象内部类Sync的解析。
CountDownLatch类:
CountDownLatch类中文翻译为闭锁,它的工作机制是设定一个初值,在初值减为0之前调用await方法会使当前线程进入等待状态,调用countDown减到0时会将其它等待的线程唤醒。和Semaphore类似,它的功能也主要由继承AQS构建Sync实现。
内部类Sync:
1 private static final class Sync extends AbstractQueuedSynchronizer { 2 private static final long serialVersionUID = 4982264981922014374L; 3 4 Sync(int count) { 5 setState(count); 6 } 7 8 int getCount() { 9 return getState(); 10 } 11 12 protected int tryAcquireShared(int acquires) {//如果state减到1,返回都为正;如果没有减到1,返回都为负 13 return (getState() == 0) ? 1 : -1; 14 } 15 16 protected boolean tryReleaseShared(int releases) { 17 // Decrement count; signal when transition to zero 18 for (;;) { 19 int c = getState(); 20 if (c == 0) 21 return false; 22 int nextc = c-1;//nextc是c-1 23 if (compareAndSetState(c, nextc))//每次调用都将state减去一 24 return nextc == 0; 25 } 26 } 27 }
await方法:
sync调用acquireSharedInterruptibly方法会调用上面实现的tryAcquireShared,如果state没减到0就返回负,线程等待进入队列。
1 public void await() throws InterruptedException { 2 sync.acquireSharedInterruptibly(1); 3 }
countDown方法:
sync调用releaseShared方法会调用上面实现的tryReleaseShared,然后会调用AQS的doReleaseShared唤醒队首的线程,队首的线程获取资源时会唤醒后面线程(因为此时调用tryAcquireShared返回值一直为正),后面线程唤醒再后面线程,直至全部唤醒。
1 public void countDown() { 2 sync.releaseShared(1); 3 }
可重入锁的实现要复杂一点,另开一篇。