Java多线程并发器之AbstractQueuedSynchronizer分析
来源:互联网 发布:波士顿矩阵图的优缺点 编辑:程序博客网 时间:2024/06/07 00:07
AbstractQueuedSynchronizer
AbstractQueuedSynchronizer是Java并发工具包中最重要的工具,它是一个抽象类,为Java的各种同步器,锁等提供了并发抽象,是由大名鼎鼎的Doug Lea完成。
java.util.concurrent提供了很多并发工具类,其中很多都是基于AbstractQueuedSynchronizer实现的。如,ReentrantLock、ReentrantReadWriteLock、CountDownLatch、CyclicBarrier【CyclicBarrier内部使用ReentrantLock和Condition实现,间接使用了AbstractQueuedSynchronizer】、Semaphore、各种BlockingQueue【与CyclicBarrier类似,内部使用了ReentrantLock】、ConcurrentHashMap【与CyclicBarrier类似,内部使用了ReentrantLock】、CopyOnWriteArrayList【与CyclicBarrier类似,内部使用了ReentrantLock】等。由此可以看出AbstractQueuedSynchronizer的重要性。
AbstractQueuedSynchronizer内部使用了compareAndSwap(CAS)无锁操作来实现锁的,compareAndSwap()是使用native方法实现的,其提供了一个原子语义上的操作,即要更新一个变量的值时,如果该变量的原始值是我认为的原始值,那么我就更新成功,否则就更新失败,更新失败就一直尝试更新,若干次之后总会更新成功。而不是像synchronized那样从操作系统层面上加锁,因此引入AbstractQueuedSynchronizer之后大大优化了Java的锁性能。
既然java.util.concurrent中这么多并发工具选择扩展AbstractQueuedSynchronizer来实现锁、条件队列和条件谓词,那么,如何使用AbstractQueuedSynchronizer来实现我们自己的同步工具呢?
如果要扩展AbstractQueuedSynchronizer,强烈建议使用组合而非继承进行扩展,可以在自己的同步工具内部维持一个私有的AQS的子类,
这个AbstractQueuedSynchronizer的子类只需覆盖AbstractQueuedSynchronizer中的【当只支持独占操作时,即排它锁】
- tryAcquire(int);
- tryRelease(int);
- isHeldExclusively()方法【tryAcquire返回true时表示设置state成功,获取到锁了,返回false表示没获取到】;
或者覆盖AbstractQueuedSynchronizer中的【当支持共享获取时,即共享锁】,
- tryAcquireShared(int);
- tryReleaseShared(int)【tryAcquireShared返回值小于0时表示没获取到锁,等于0表示获取到锁但是后续线程获取不到锁,大于0表示获取到锁&后续线程可能也会获取到锁】;
这些方法在AbstractQueuedSynchronizer中直接是throw new UnsupportedOperationException()。
在自己的工具类中使用子类继承AbstractQueuedSynchronizer时,直接实现这些方法,然后就可以使用这个子类的
- acquire(int);
- release(int);
- acquireShared(int);
- releaseShared(int);
来获取锁了。注意:AbstractQueuedSynchronizer中acquire(int)、release(int)、acquireShared(int)、releaseShared(int)都会调用子类中【因为被覆盖了】带有前缀try的版本来判断某个操作是否能执行(比如acquire(int)内部其实是会调用tryAcquire(int)来尝试获取锁,而tryAcquire(int)是AbstractQueuedSynchronizer本身就实现好的),所以我们只需要实现有前缀try的获取许可的方法版本。
ReentrantLock
ReentrantLock内部使用了AbstractQueuedSynchronizer来实现锁。其内部使用Sync扩展了AbstractQueuedSynchronizer。
如ReentrantLock中的Sync类:
abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; /** * Performs {@link Lock#lock}. The main reason for subclassing * is to allow fast path for nonfair version. */ abstract void lock(); /** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; } protected final boolean isHeldExclusively() { // While we must in general read state before owner, // we don't need to do so to check if current thread is owner return getExclusiveOwnerThread() == Thread.currentThread(); } final ConditionObject newCondition() { return new ConditionObject(); } // Methods relayed from outer class final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } final int getHoldCount() { return isHeldExclusively() ? getState() : 0; } final boolean isLocked() { return getState() != 0; } /** * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state }}
其中,ReentrantLock内部的非公平锁和公平锁实现略有差别:
非公平锁为:
static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }}
公平锁:
static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ 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; }}
然后调用NonFairSync或FairSync的lock()方法就可以获取到锁了。
由上可知,我们其实只需要实现AbstractQueuedSynchronizer中的try前缀方法就好了,然后我们就可以自由的通过acquire()或者release()等方法来获取锁和释放锁。
Semaphore
与ReentrantLock一样,Semaphore内部使用了AbstractQueuedSynchronizer来实现锁。其内部使用Sync扩展了AbstractQueuedSynchronizer。
Semaphore中的Sync类:
/** * Synchronization implementation for semaphore. Uses AQS state * to represent permits. Subclassed into fair and nonfair * versions. */abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 1192457210091910933L; Sync(int permits) { setState(permits); } final int getPermits() { return getState(); } final int nonfairTryAcquireShared(int acquires) { for (;;) { int available = getState(); int remaining = available - acquires; 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"); if (compareAndSetState(current, next)) return true; } } final void reducePermits(int reductions) { for (;;) { int current = getState(); int next = current - reductions; if (next > current) // underflow throw new Error("Permit count underflow"); if (compareAndSetState(current, next)) return; } } final int drainPermits() { for (;;) { int current = getState(); if (current == 0 || compareAndSetState(current, 0)) return current; } }}
其中,非公平信号量和公平信号量实现略有差别:
非公平信号量:
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); }}
公平信号量:
static final class FairSync extends Sync { private static final long serialVersionUID = 2014338818796000944L; FairSync(int permits) { super(permits); } protected int tryAcquireShared(int acquires) { for (;;) { if (hasQueuedPredecessors()) return -1; int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } }}
然后调用NonFairSync或者FairSync的acquireShared(int)方法就可以获取到信号量了。
自定义简单的AbstractQueuedSynchronizer实现类:
首先,扩展AbstractQueuedSynchronizer类,
class MyLock { private Sync sync; private static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 3633529035712707665L; @Override public boolean tryAcquire(int acqiure) { return compareAndSetState(0, 1); //不是可重入的 } @Override public boolean tryRelease(int acqiure) { setState(0); // 不是可重入的 return true; } } MyLock() { this.sync = new Sync(); } public void lock() { sync.acquire(1); } public void unlock() { sync.release(1); }}
其次,构建线程使用自己实现的同步工具,
class SyncThread implements Runnable { private MyLock lock; public SyncThread(MyLock lock) { this.lock = lock; } public void run() { lock.lock(); for (int i = 0; i < 6; i ++) { System.out.print(ConcurrentTest.i++ + " "); } lock.unlock(); }}
最后,测试自己实现的同步工具,
public class ConcurrentTest { public static int i = 1; public static void main(String[] args) { MyLock lock = new MyLock(); ExecutorService exec = new ThreadPoolExecutor(3, 1000, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2000), new ThreadPoolExecutor.CallerRunsPolicy()); exec.execute(new SyncThread(lock)); exec.execute(new SyncThread(lock)); exec.execute(new SyncThread(lock)); }}
输出为,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
总结
AbstractQueuedSynchronizer是Java中非常基础并且非常重要的抽象同步器。Java中诸多同步工具扩展了AbstractQueuedSynchronizer来实现锁、条件队列和条件谓词。我们也可以自己扩展AbstractQueuedSynchronizer来实现锁等。不过在工作中基本不会自己来实现AbstractQueuedSynchronizer,因为Java提供的ReentrantLock等等工具已经能够基本满足开发需求。
喜欢的可以关注微信公众号:
更多文章
- 我自己的头条号: 并发器AbstractQueuedSynchronizer
- Java多线程并发器之AbstractQueuedSynchronizer分析
- Java并发之AbstractQueuedSynchronizer分析
- java并发之AbstractQueuedSynchronizer
- Java多线程之AbstractQueuedSynchronizer
- java并发编程之AbstractQueuedSynchronizer
- 读JAVA并发包之AbstractQueuedSynchronizer
- Java并发包--AbstractQueuedSynchronizer
- 【Java并发】详解 AbstractQueuedSynchronizer
- java 并发包-AbstractQueuedSynchronizer
- JAVA FutureTask之AbstractQueuedSynchronizer 源码分析
- java 并发编程 AbstractQueuedSynchronizer 加锁和解锁分析
- java并发编程--AbstractQueuedSynchronizer的tryLock()方法分析(六)
- java并发编程--AbstractQueuedSynchronizer条件锁分析(四)
- java并发编程--AbstractQueuedSynchronizer加锁和解锁分析(二)
- java并发:AbstractQueuedSynchronizer的介绍和原理分析
- Java JUC并发 AbstractQueuedSynchronizer学习
- Java并发编程(一)--AbstractQueuedSynchronizer
- Java并发学习(三)-AbstractQueuedSynchronizer
- 战略管理与业务流程管理
- POJ
- 互联网的下半场,哪些玩法会引发行业巨变?
- tf.global_variables或者tf.all_variables的用法
- Linux-四-常见符号-(20170516)
- Java多线程并发器之AbstractQueuedSynchronizer分析
- 爱测未来开发-Zabbix的使用 API的调用
- FlashFXP5.4 注册码
- linux下建站软件安装
- [IO系统]17 IO调度器-DEADLINE
- Linux: android studio AVD emulator启动不了 | openGL | glx
- android textView设置粗体
- Visual Studio调试报错不自动断点,显示程序已结束运行
- 【数据结构作业】实现任意三种静态或动态查找