
AbstractQueuedSynchronizer,简称AQS,是Java并发包里一系列同步工具的基础实现,原理是根据状态位来控制线程的入队阻塞、出队唤醒来处理同步。
?????? AQS内部维护一个CLH队列来管理锁。
线程会首先尝试获取锁,如果失败,则将当前线程以及等待状态等信息包成一个Node节点加到同步队列里。
接着会不断循环尝试获取锁(条件是当前节点为head的直接后继才会尝试),如果失败则会阻塞自己,直至被唤醒;
而当持有锁的线程释放锁时,会唤醒队列中的后继线程。
自定义基于AQS的同步工具时,可以选择覆盖以下几个方法实现同步状态的管理:
?????? 1、boolean tryAcquire(int)//尝试获取独占锁
?????? 2、boolean tryRelease(int)//尝试释放独占锁
?????? 3、int tryAcquireShared(int)//尝试获取共享锁
?????? 4、boolean tryReleaseShared(int)//尝试释放共享锁
?????? 5、boolean isHelodExclusively()//当前线程是否获得了独占锁
?????? 这些方法的实现应当是无阻塞的。
CountDownLatch的countDown()释放操作实际上是sync.releaseShared(1) 其中Sync是AQS的一个子类实例
???????????????????????????? await()操作实际上是sync.acquireSharedInterruptibly(1)
CyclicBarrier实现主要基于ReentrantLock
Semaphore也是基于AQS,有一个内部类Sync,分别有公平Sync和非公平Sync
各个锁的优缺点
?????? 内核锁:基于内核对象构造的锁机制,就是通常说的内核构造模式。
???????????????????? 优点:cpu利用最大化。它发现资源被锁住,请求就排队等候。线程切换到别处干活,直到接受到可用信号,线程再切回来继续处理请求。
???????????????????? 缺点:托管代码->用户模式代码->内核代码损耗、线程上下文切换损耗。
???????????????????????????????????? 在锁的时间比较短时,系统频繁忙于休眠、切换,是个很大的性能损耗。
?????? 自旋锁:原子操作+自循环。通常说的用户构造模式。?? 线程不休眠,一直循环尝试对资源访问,直到可用。
???????????????????? 优点:完美解决内核锁的缺点。
???????????????????? 缺点:长时间一直循环会导致cpu的白白浪费,高并发竞争下、CPU的消耗特别严重。
???????????????????????????????? 基于CAS操作,需要硬件配合。需要保证各个CPU缓存一致性。没办法保证公平性。
?????? 混合锁:内核锁+自旋锁。 混合锁是先自旋锁一段时间或自旋多少次,再转成内核锁。
???????????????????? 优点:内核锁和自旋锁的折中方案,利用前二者优点,避免出现极端情况(自旋时间过长,内核锁时间过短)。
???????????????????? 缺点: 自旋多少时间、自旋多少次,这些策略很难把控。
?????? Java没有提供自旋锁的API,但是默认使用了自旋锁优化
?????? 自旋锁(spin lock)与互斥量(mutex)的比较
?????????????? 自旋锁是一种非阻塞锁,也就是说,如果某线程需要获取自旋锁,但该锁已经被其他线程占用时,该线程不会被挂起,而是在不断的消耗CPU的时间,不停的试图获取自旋锁。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-87102-1.html
请多提宝贵意见