java可重入锁ReentrantLock原理
2016-04-17 22:41
956 查看
ReentrantLock
JUC中ReentrantLock实现了独占模式重入锁,对于可重入,此类的注释是这样的:当一个线程锁住ReentrantLock,但是没有解锁,这个线程再执行加锁方法会返回成功,并获得这把锁
ReentrantLock类图
由上图可知,ReentrantLock包含两个静态属性,一个是java 序列化Serializable使用的属性serialVersionUID,一个是sync,sync是内部类Sync的实例,ReentrantLock中还包含两个另外两个子类FairSync,NonfairSync。它们都继承自Sync类。FairSync是公平锁的实现方式,NonfairSync是非公平锁的实现方式。他们两都实现了可重入。
ReentrantLock初始化
ReentrantLock有两个不同的初始化方法public ReentrantLock() { //默认方式:设置sync属性为非公平模式锁NonfairSync实例 sync = new NonfairSync(); } public ReentrantLock(boolean fair) { //根据用户传入是否公平参数,设置sync属性为非公平模式锁NonfairSync或者公平模式锁FairSync实例 sync = fair ? new FairSync() : new NonfairSync(); }
ReentrantLock加锁解锁
ReentrantLock解锁解锁执行的都是sync的方法//加锁 public void lock() { sync.lock(); } //可中断加锁 public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } //尝试加锁 public boolean tryLock() { return sync.nonfairTryAcquire(1);//使用非公平模式获取一次锁 } //带时间限制的尝试加锁 public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } //释放锁 public void unlock() { sync.release(1); }
Sync加锁解锁
Sync的加锁方法是一个abstract 方法,交由子类实现abstract void lock();
公平重入锁
其中公平重入锁方式直接调用aqs的acquire,然后自身实现了aqs acquire方法会调用的tryAcquire方法(aqs的流程详见上一篇aqs的介绍)。其中tryAcquire获取锁首先会判断当前state是否为0。如果不为0则代表锁已被锁住,如果被锁住,则查看占用的线程是否为当前线程。如果是当前线程占用了这个锁,则可重入,进行state增加。state可以表示持有者重入次数。
如果为0,则判断当前线程代表的节点在队列中有没有在排队的前任,如果没有在排队的前任则尝试获取锁。因为新加入获取锁队列的节点都是加在队列的尾部。而只有队列中没有前任在排队获取锁的节点才能尝试获取锁,维持了一个先进先出的规则。所有线程都是根据进入顺序去持有锁的,是公平的方式。
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; } } //如果持有锁的为自己,则重入state+=acquires 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 在调用lock方法时会快速cas尝试修改state状态0->1,如果成功则设置锁持有者为自身,不去管是否有其他线程在等待。是非公平的方式。当cas不成功时,则调用acquire,并且NonfairSync 自身也和FairSync类一样,实现了acquire会调用的tryAcquire方法。tryAcquire方法使用的是父类Sync的非公平尝试获取锁方法nonfairTryAcquireprotected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }
nonfairTryAcquire方法与FairSync类的tryAcquire不同点在于这个方法实现的不公平方式不会判断是否有前任在排队。直接进行尝试获取锁。会造成插队情况,是不公平获取锁的形式,但是比公平方式少了一些判断,性能更优。
nonfairTryAcquire的重入方式与公平锁FairSync的一样。
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { //如果状态为0,当前锁未锁住,尝试cas修改状态 if (compareAndSetState(0, acquires)) { //设置当前线程为锁的独占线程 setExclusiveOwnerThread(current); return true; } } //如果占据锁的线程是当前线程,state+=acquires else if (current == getExclusiveOwnerThread()) { 4000 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; }
ReentrantLock unlock
ReentrantLock unlock调用的Sync的父类AQS的release方法释放锁。而Sync实现了release方法会调用的tryRelease。tryRelease会使锁状态state减少,调用一次则state减少1,代表重入次数减少一次。当减少到为0时,表示当前线程没有持有该锁,将锁的持有者置为空。protected final boolean tryRelease(int releases) { //state-=releases int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; //如果state为0,设置锁的所有者为空 setExclusiveOwnerThread(null); } setState(c); return free; }
总结
ReentrantLock的重入为当持有锁的为当前线程时,重入,将锁状态state增加。ReentrantLock的公平非公平模式,交由Sync的两个子类控制,区别在于公平模式只有没有前任在排队的情况下才可以获取锁。公平模式不进行这个判断。直接尝试获取锁,可插队。
相关文章推荐
- JSR-303验证框架在Springmvc中的应用
- Java断言
- 20145239杜文超 《Java程序设计》实验二 Java面向对象程序设计实验报告
- 2.为什么在写了equals方法之后还要写hashcode方法
- java设计模式之观察者模式
- JAVA常见问题解决办法汇总
- 20145320 《Java程序设计》第七周学习总结
- 导入外部jar包的方法
- eclipse创建MAVEN仓库项目
- java学习笔记(2)基本数据类型对象包装类
- json中date类型数据为空造成转JAVA对象失败
- 20145127《java程序设计》第七周学习总结
- Spring-1 之入门
- 20145335郝昊《java程序设计》第7周学习总结
- Eclipse常用快捷键
- 20145310 《Java程序设计》第7周学习总结
- Java 继承与接口
- 20145118《Java程序设计》 第7周学习总结
- java 面向对象
- 20145328 《Java程序设计》第7周学习总结