加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

java并发-14-可重入锁

(2018-04-21 13:28:18)
分类: java

1.      介绍

可重入锁是指能够重复进入的锁。例如一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法,而无需重新获得锁。场景:数据库事务操作,add操作将会获取锁,若一个事务当中多次add,就应该允许该线程多次进入该临界区。

synchronized关键字和ReentryLock都是可重入锁。

 

2.      可重入锁的作用:避免死锁

在以下程序中,子类改写了父类的synchronized 方法,然后调用父类中的方法,此时如果内置锁不是可重入的,那么这段代码将产生死锁。由于 Widget LoggingWidgetdoSomething方法都是 synchronized 方法,因此每个doSomething方法在执行前都会获取 Widget 上的锁。然而如果内置锁不是可重入的,那么调用super.doSomething( )时无法获得 Widget 上的锁,因为这个锁已经被持有,从而线程将永远停顿下去,等待一个永远也无法获得的锁。重入则避免了这种死锁情况的发生。

http://s12/mw690/002i2qf8zy7jRxlSshteb&690

 

3.      ReentryLock

ReentryLock重写了AQS中的tryAcquiretryRelease方法。可以看到ReentryLock默认构造器是非公平锁,内部执行都利用了属性syncsync.locksync.release(1)等方法,Sync类继承了AQS。每重入一次(当前线程是持有锁的线程),那么AQS(ReentryLock继承)state就会加1,每释放一次锁,state就会减1

具体的for(;;)自旋获取锁参见AQS中的acquire方法中的acquireQueued

 

public class ReentrantLockimplements Lock, java.io.Serializable {
private static final long serialVersionUID= 7373984872572414699L;

private final Sync sync;


abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID= -5179523762034025860L;


abstract void lock();


final booleannonfairTryAcquire(intacquires) {
final Thread current = Thread.currentThread();
int
c = getState();
            if
(c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current)
;
                    return true;
}
            }
else if (current == getExclusiveOwnerThread()) {
intnextc = c + acquires;
                if
(nextc<</span>0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
                return true;
}
return false;
}

protected final booleantryRelease(intreleases) {
intc = 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 booleanisHeldExclusively() {
// 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 ConditionObjectnewCondition() {
return new ConditionObject();
}

// Methods relayed from outer class

final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}

final intgetHoldCount() {
return isHeldExclusively() ? getState() : 0;
}

final booleanisLocked() {
return getState() != 0;
}


private void readObject(
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject()
;
setState(0); // reset to unlocked state
}
    }


public ReentrantLock() {
sync = new NonfairSync();
}


public ReentrantLock(booleanfair) {
sync = fair ? new FairSync() : new NonfairSync();
}

public void lock() {
sync.lock();
}

     publicbooleantryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

public void unlock() {
sync.release(1);
}
}
 

 

下面以非公平锁为例,介绍了具体实现方法。最终tryAcquire调用了sync中的nonfairTryAcquire方法,试图利用CAS方法改变AQS中当前节点状态,如果失败则按照acquire方法进行自旋或挂起。


static final class NonfairSyncextends Sync {
private static final long serialVersionUID= 7316153563782823691L;


final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread())
;
        else
acquire(1);
}

protected final booleantryAcquire(intacquires) {
return nonfairTryAcquire(acquires);
}
}

 

参考文献

[1] https://www.cnblogs.com/yutingliuyl/p/7352491.html

[2] https://www.cnblogs.com/yuyutianxia/p/4296220.html

[3] https://juejin.im/post/5921927c44d904006cca9720

[4]https://www.zhihu.com/question/23284564

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有