Java Concurrent ReentrantLock(Ja
前言
Reentrant是一种可重入锁,是一种递归无阻塞的同步机制。实现了和synchronized类似的同步策略。与synchronized配合使用的wait、notify、notifyall等函数,由Codition负责提供,这个后续另外会说。
使用
1、在使用上与synchronized差异的是 实现lock接口的reentrant需要手动的去lock和release,因为synchronized是JVM也就是Java语法层面实现的,而Lock是JDK里面实现的。相对于sychronized来说,我们使用时要比synchronized更加严谨,因为忘记释放锁非常容易导致死锁。建议选择在finally中进行锁的释放
2、lock实现的锁粒度可以控制更加小
3、Lock 实现能更支持更多高级的特性,比如说锁超时等。
4、因为是JDK实现,所以具有了更多特性的高级锁比如说:read lock、write lock,并且支持我们自定义特殊的锁,这个虽然通常用不太到,但必要时是非常有用的。
demo:首先是使用synchronize,感受一下
class Test1 {
private static volatile int condition = 0;
private static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread A = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
while (!(condition == 1)) {
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.println("a executed by notify");
}
}
});
A.start();
Thread.sleep(2000);
condition = 1;
synchronized (lock) {
lock.notify();
}
}
}
然后是使用Lock
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Test2 {
private static volatile int condition = 0;
private static Lock lock = new ReentrantLock();
private static Condition lockCondition = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
Thread A = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
while (!(condition == 1)) {
lockCondition.await();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
System.out.println("a executed by condition");
}
});
A.start();
Thread.sleep(2000);
condition = 1;
lock.lock();
try {
lockCondition.signal();
} finally {
lock.unlock();
}
}
}
原理
开始看源码:
首先可以看到ReentrantLock实现了Lock
和Serializable
接口,序列化不多说,Lock定义了是现在JDK中锁的规范,然后类中持有一个Sync
对象,其中Sync是ReentrantLock的一个静态内部类,这是整个ReentrantLock的基础,Sync继承自AQS,换句话说AQS也就是ReentrantLock的实现基础。
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
/**
* Base of synchronization control for this lock. Subclassed
* into fair and nonfair versions below. Uses AQS state to
* represent the number of holds on the lock.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
然后往后看会得到另外几个静态内部类:FairSync
、NonfairSync
,他们均继承自Sync
这两个区别最大的操作是:
如果当前线程不是锁的占有者,则NonfairSync
并不判断是否有等待队列,直接使用CAS去进行锁的占用;
如果当前线程不是锁的占有者,则FairSync
则会判断当前是否有等待队列,如果有则将自己加到等待队列尾;
这其实就是公平锁&非公平锁的实现,默认非公平。
下面的代码中,我加了几行注释,大家注重关注下可重入及公平非公平是如何实现的。
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
它这里使用的是Sync里面的实现:
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
@ReservedStackAccess
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;
}
然后是FairSync的实现
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
@ReservedStackAccess
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;
}
}
看到这里,大体已经能猜到具体实现了。ReentrantLock中维护着一个AQS,然后竞争锁的线程是在这里排队的,然后通过对应的CAS操作进行锁的争用。具体的实现参考AQS及CAS。
默认非公平:
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
可以很明显的看到底层实现几乎完全依赖于AQS,其实就是AQS包了一层罢了。
public void lock() {
sync.acquire(1);
}
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);
}
public int getHoldCount() {
return sync.getHoldCount();
}