Java 1.7 ReentrantLock源码解析
Posted Mr-yuenkin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 1.7 ReentrantLock源码解析相关的知识,希望对你有一定的参考价值。
1. 简介
可重入锁是基于AQS实现的,和synchronized有相同的语义,同时有更多的扩展功能,比如可以tryLock和在指定时间内获取锁、响应中断获取锁等。典型用法如JDK 1.7中的示例:
lock.lock(); // block until condition holds
* try
* // ... method body
* finally
* lock.unlock()
*
有两种模式:公平模式和非公平模式。公平和非公平的的含义见Java1.7 ReentrantReadWriteLock源码解析,类结构图如下所示:
主类ReentrantLock就一个sync成员变量,借助其实现lock/unlock功能。
2. ReentrantLock
2.1 lock
public void lock()
sync.lock();
lock函数实现synchronized语义:1、如果当前没有线程占有锁,立即返回,设置独占标识且state值设置为1;2、如果当前线程已经占有锁了,立即返回,设置state+=1;3、如果其他线程已经占有锁了,当前线程会一直等待,直到获取到锁。
2.2 unlock
public void unlock()
sync.release(1);
tryLock函数释放锁,如果当前线程占有锁,则设置state-=1,减1后如果state为0了,则清空独占线程标识(setExclusiveOwnerThread(null));如果当前线程没有占有锁就调用unlock方法,则抛出异常IllegalMonitorStateException。
2.3 lockInterruptibly
public void lockInterruptibly() throws InterruptedException
sync.acquireInterruptibly(1);
lockInterruptibly函数实现了synchronized语义,但是支持中断(当其他线程调用了interrupt方法)。
2.4 tryLock
public boolean tryLock()
return sync.nonfairTryAcquire(1);
tryLock函数尝试获取锁(不管公平模式还是非公平模式都不排队)。如果锁已经被其他线程获取了直接返回false,否则,返回true。
2.5 带超时的tryLock
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
和2.4上面的不同,这个支持中断且在公平模式下是要排队的。如果当前没有线程获取到锁,直接返回true,否则,等待直至超时或被中断。如果不想排队又想要支持超时,你可以这么写:if(lock.tryLock() || lock.tryLock(timeout, unit) ) ... 。
2.6 getHoldCount
public int getHoldCount()
return sync.getHoldCount();
getHoldCount函数返回当前线程重入锁了几次(也有可能是0)。
1. Sync
3.1 nonfairTryAcquire
final boolean nonfairTryAcquire(int acquires)
final Thread current = Thread.currentThread();
int c = getState();
// 如果没有线程占有锁且设置state成功,则设置线程独占标识并返回true
if (c == 0)
if (compareAndSetState(0, acquires))
setExclusiveOwnerThread(current);
return true;
// 如果是重入的,设置state+=acquires并返回true(如果int没越界)
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;
nonfairTryAcquire函数尝试获取锁,不排队方式,如果当前没有线程占有锁或者是重入的,返回true;否则,返回false。
3.2 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;
// 如果state==0了,清空线程独占标识
setExclusiveOwnerThread(null);
// 肯定是占有锁了,不用循环CAS了,直接设置
setState(c);
return free;
tryRelease函数释放锁,如果state为0了,则要清空线程独占标识。
4. NonfairSync
static final class NonfairSync extends Sync
private static final long serialVersionUID = 7316153563782823691L;
/**
* 先插个队尝试获取锁(大多数情况会成功的),如果失败了再调用tryAcquire
* 里面会考虑重入的情况。
*/
final void lock()
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
// 可以直接插队获取锁的且会考虑重入情况
protected final boolean tryAcquire(int acquires)
return nonfairTryAcquire(acquires);
5. FairSync
static final class FairSync extends Sync
private static final long serialVersionUID = -3000897897090466540L;
final void lock()
acquire(1);
/**
* 公平模式下获取锁的方式,如果state==0且前面没有线程排队才能获取锁;
* 或者是重入的情况。
*/
protected final boolean tryAcquire(int acquires)
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0)
// c==0且前面没有线程排队且CAS设置成功,则设置线程独占标识,返回true
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;
以上是关于Java 1.7 ReentrantLock源码解析的主要内容,如果未能解决你的问题,请参考以下文章