常用方法
lock()
尝试去竞争锁,竞争到了则可以执行,竞争不到,则加入到Node队列中排队等待执行。在公平锁和非公平锁中实现大致相同,主要是在竞争的时候有所不同。
其是否竞争到主要是依据AQS中的变量state,用0代表无锁状态,哪个线程通过cas的方式把state从0改变了,则代表当前线程竞争到锁了。
如果没有竞争到的线程,也会通过AQS中的Node双向链表进行管理,会通过Node记录线程以及Node的状态,对线程进行存储,方便后续在竞争到锁的节点释放时进行唤醒后续线程。
public void lock() {
sync.lock();
}
tryLock()
尝试去竞争锁,竞争成功则直接占有锁。只会尝试一次。可以参考Sync内部类的方法描述。
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
tryLock(long timeout, TimeUnit unit)
在单位时间内判断是否能获取锁。
其本质也是AQS中去尝试获取锁,如果获取不到,则通过LockSupport.park(timeout)进行按时间的阻塞。到阻塞时间没有获取到锁之后返回false,如果在规定时间内调用了unpark方法,则返回true。标识获取到锁了
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
unlock
unlock本质就是把state状态减一,然后唤醒在链表中的等待节点
public void unlock() {
sync.release(1);
}
newCondition
newCondition方法主要是依托于Aqs。
其主要原理是形成单独的当前条件的Condition链表,在初始化状态时,并不在竞争锁的Node双向链表中,在达到了一定条件之后即调用signal或者signalAll方法之后会把当前节点放置到竞争锁的Node链表中再去竞争
public Condition newCondition() {
return sync.newCondition();
}
构造方法
ReentrantLock() 默认非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair)
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
内部类Sync(基于aqs的同步器)
整体思想
方法描述
nonfairTryAcquire
非公平的去获取锁,为什么说是非公平,因为没有判断前边的链表上是否有正在排队的节点。可能会出现上一个节点刚释放锁,排队的节点和当前插入的节点竞争的情况。
为什么是可重入的,因为在获取不到锁的时候判断如果是当前线程,则可以继续获取到锁。
// 非公平的尝试获取锁
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// 获取当前锁的状态。基于aqs的实现
// aqs中的state会代表整体锁的情况,在ReentrantLock中state为0代表当前锁是空闲的
int c = getState();
if (c == 0) {
// 如果锁是空闲的,则尝试去占有。通过cas的方式设置
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 此处为可重入的原理,如果判断线程拥有者是当前线程,则设置state的值,并且标识获取到锁了
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;
}
tryRelease
释放锁
其实针对ReentrantLock来说,是否上锁主要是判断state的值,释放锁也就是让累加上的state的值恢复为0。
//释放锁
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;
}
newCondition
其主要用途是在达成某个条件之后,才会让当前对象参与竞争。通过await方法进入对应的ConditionObject链对象中,直到当前ConditionObject调用signal或者signAll方法之后,才会把当前对象放置到ReentrantLock的Node链中
final ConditionObject newCondition() {
return new ConditionObject();
}
NonfairSync(基于Sync的非公平同步器)
lock
会调用aqs的acquire方法,主要是尝试获取锁,然后再队列里竞争锁,竞争到了则执行,并且改变链表中的node头结点为当前节点。如果获取不到,则park住当前线程。
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
FairSync(基于Sync的公平同步器)
tryAcquire
尝试获取锁,但是会在获取锁的时候先判断Node链表中是否有前驱节点,没有的话,才回去竞争锁。
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;
}