ReentrantLock 是 java并发包下互斥锁,功能和synchronized差不多。但是他们的实现原理有很大差别,是基于操作系统互斥量实现的,依赖于JVM的实现,而ReentrantLock 是AQS的经典实现,是java 代码层面的实现的。随着jvm的升级,对锁的优化越来越好。我们在选择锁的时候,synchronized 和ReentrantLock 的性能不在是主要考虑的因素,可以结合自己的业务场景,合理的选择锁的实现。
1、ReentrantLock的用法
public class ReentrantLockTest {
private static ReentrantLock lock = new ReentrantLock();
private static int i = 0;
public static void main(String[] args) {
try{
lock.lock();//获取锁
i++;
}finally {
lock.unlock();//一定要在finally中释放锁,否则处理过程中出现异常,锁永远不会被释放
}
}
}
2、ReentrantLock 的原理
ReentrantLock 是基于AQS独占锁实现的,前文已经说过了AQS的原理。这里就说说ReentrantLock 的实现。
之前说过,AQS作为同步器的基础,维护了一个state(同步状态),这个state含义的由子类自己定义。
在 ReentrantLock 中state 被定义为锁的重入次数(所以又叫可重入锁)。当state=0,说明没有线程拥有锁,线程每次获取锁就把state + 1。相反每次释放锁state - 1,重入了多少次锁,就必须释放多少次锁。ReentrantLock 又分为公平锁 和非公平锁。下面分别看看代码如何实现。
先看看公平锁
final void lock() {
//调用AQS 中的acquire 方法。acquire 会调用tryAcquire 来判断是否获取锁成功
acquire(1);
}
/**
* tryAcquire 方法在AQS中说过,
* 是留给子类现实独占模式获取锁。
* 返回true 表示获取成功,false表示获取锁失败
*
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {//表示没有当前线程拥有锁
//之前没有节点,设置state属性,并将拥有锁的线程设置为当前线程
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;
}
在看看非公平锁
// 与公共锁相比。线程一开始就尝试获取锁,并不管是否有线程拥有锁或者在排队等待,
// 导致的结果就是先排队的不一定比后面来的先 获取到锁
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
//尝试获取锁 直接点用了nonfairTryAcquire
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
//与公平锁相比,就是不判断前面有没有线程在等待。其他相同
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;
}
熟悉了AQS的原理之后,在来看ReentrantLock 感觉很简单,只需要实现尝试获取锁的方法就可以了,那么问题来了,我们可用实现这个方法做一个分布式锁吗?
网友评论