AQS(5):ReentrantLock
2016-04-04 11:53
429 查看
ReentrantLock在行为和语义上与synchronized类似,但是更具可扩展性。该锁是可重入的,并且有公平和非公平两种选项。在学习了AQS之后,理解ReentranLock就更容易了。我们知道,AQS已经提供了状态管理,阻塞,队列管理等功能。继承于它的同步工具类只需要实现诸如tryAcquire,tryRelease等基础方法就能实现锁的功能。自然,在ReentrantLock中也包含了Synchronizer对象。
该类中定义了一个静态抽象类Sync作为公平Sync和非公平Sync的基类,定义了公共的tryRelease方法。
这个方法非常简单,state可以简单理解为如果大于0表示持有锁时重入次数,如果等于0则没有线程持有锁。因此简单的判断release后是否为0并重新设置state就可以了。该类中还定义了一个nonfairTryAcquire方法。
该方法的思路仍然是通过state确定是否加锁成功。首先如果state=0,即无人持有锁,那么通过CAS更改state,注意,此处由于可能存在竞争,必须使用CAS而非普通的比较设置两段操作。如果当前线程已经持有锁,那么本次是重入,仅记录一下重入状态就可以了。
接下来是设计公平和非公平的Sync具体子类。我们先来看NonfairSync中的lock方法。
这就体现了非公平性,他会直接通过判断state强行尝试一次,而不是在队列中排队通过acquire来取得锁。我们整体描述一下非公平锁的lock流程。首先,根据state判断能否立即加锁成功,如果不能则调用acquire;在acquire过程中,调用tryAcquire,这个方法中又会判断一次state,如果又失败,就向同步队列添加一个节点.这种情况下只有当该节点前驱是头结点的时候才会尝试用tryAcquire取得锁,否则就被阻塞。可以看到,在这个过程中,非公平锁至少会两次尝试通过CAS更改state来取得锁。
在fairSync中的tryAcquire方法流程就不同了,由于考虑到公平性,不能只根据state就决定是否取得锁。该过程中,如果无人持有锁,那么判断他有没有前驱节点,如果没有,再让自己持有锁,这就是公平性的体现。
该类中的其他方法基本都是对Sync中定义方法的调用,没有其他的新意,对ReentrantLock的解析就到这里了。
该类中定义了一个静态抽象类Sync作为公平Sync和非公平Sync的基类,定义了公共的tryRelease方法。
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; }
这个方法非常简单,state可以简单理解为如果大于0表示持有锁时重入次数,如果等于0则没有线程持有锁。因此简单的判断release后是否为0并重新设置state就可以了。该类中还定义了一个nonfairTryAcquire方法。
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; }
该方法的思路仍然是通过state确定是否加锁成功。首先如果state=0,即无人持有锁,那么通过CAS更改state,注意,此处由于可能存在竞争,必须使用CAS而非普通的比较设置两段操作。如果当前线程已经持有锁,那么本次是重入,仅记录一下重入状态就可以了。
接下来是设计公平和非公平的Sync具体子类。我们先来看NonfairSync中的lock方法。
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
这就体现了非公平性,他会直接通过判断state强行尝试一次,而不是在队列中排队通过acquire来取得锁。我们整体描述一下非公平锁的lock流程。首先,根据state判断能否立即加锁成功,如果不能则调用acquire;在acquire过程中,调用tryAcquire,这个方法中又会判断一次state,如果又失败,就向同步队列添加一个节点.这种情况下只有当该节点前驱是头结点的时候才会尝试用tryAcquire取得锁,否则就被阻塞。可以看到,在这个过程中,非公平锁至少会两次尝试通过CAS更改state来取得锁。
在fairSync中的tryAcquire方法流程就不同了,由于考虑到公平性,不能只根据state就决定是否取得锁。该过程中,如果无人持有锁,那么判断他有没有前驱节点,如果没有,再让自己持有锁,这就是公平性的体现。
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; }
该类中的其他方法基本都是对Sync中定义方法的调用,没有其他的新意,对ReentrantLock的解析就到这里了。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python3写爬虫(四)多线程实现数据爬取
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序