作者专注于Java、架构、Linux、小程序、爬虫、自动化等技术。 工作期间含泪整理出一些资料,微信搜索【程序员高手之路】,回复 【java】【黑客】【爬虫】【小程序】【面试】等关键字免费获取资料。
目录
一、整体结构
1.Sync
三、主要方法
四、其它
一、整体结构
该类位于java.util.concurrent.locks包下
首先看一下结构:
ReentrantLock中:
3个类:Sync、NonfairSync、FairSync
若干个方法:lock()、tryLock()、unlock()、acquireInterruptibly(int arg)等
具体流程
二、三个内部类
1.Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
//抽象lock方法
abstract void lock();
//该TryAquire默认给非公平锁使用
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//判断锁的状态
int c = getState();
//锁为空闲
if (c == 0) {
//进行CAS操作,设置当前线程持有锁
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;
}
//释放锁
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
//释放锁的线程必须为持有锁的线程
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
//state为0才能释放锁
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
//如果当前线程同步是以独占的方式进行的,则返回true
protected final boolean isHeldExclusively() {
// 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 ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
//获得占用同步状态的线程
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
//获得当前线程持有锁的数量,即重入次数
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
//是否被锁定
final boolean isLocked() {
return getState() != 0;
}
//自定义饭序列化逻辑
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
2.NonfairSync
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
//首先基于AQS进行CAS操作,将0->1.若成功,则获取锁成功
//否则,执行AQS的正常同步状态获取逻辑
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
3.FairSync
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
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(AbstractQueuedSynchronizer)类里面的acquere方法中省略了acquireQueued()和selfInterrupt()。
如果tryAcquire(arg)返回成功,则说明当前线程成功获取了锁(第一次获取或者重入),由取反和&&可知,整个流程到这结束,只有当前线程获取锁失败才会执行后面的判断。addWaiter(Node.EXCLUSIVE)
部分代码描述了当线程获取锁失败时如何安全的加入同步等待队列。这部分代码可以说是整个加锁流程源码的精华,充分体现了并发编程的艺术性。
1.lock()方法
public void lock() {
sync.lock();
}
1.1 如果该lock是NonfairSync类的实例,则进入NonfairSync的lock()里:
最底层还是进入nonfairTryAcquire()方法里
1.2 如果该lock是FairSync类的实例,则进入FairSync的lock()里:
最底层是进入tryAcquire()方法里
2.tryLock()方法
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
一步到位,直接调用nonfairTryAcquire()方法
3.unlock()方法
public void unlock() {
sync.release(1);
}
4.lockInterruptibly()方法
public void lockInterruptibly() throws InterruptedException {
//调用父类AbstractQueuedSynchronizer里的方法
sync.acquireInterruptibly(1);
}
//这是父类AbstractQueuedSynchronizer的方法
public final void acquireInterruptibly(int arg)
throws InterruptedException {
//中断线程,如果成功中断,则抛出异常
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
这是Lock锁和synchronized锁相比独有的特性之一,获取锁的线程是可以被中断的,而且中断的时候抛出异常;
四、其它
由上面的图可知,ReentrantLock里面的最最基本的方法是tryAcquire()、nonfairTryAcquire()和tryRelease()
把这两个方法搞懂了,这个类也就明白很大一部分了
另外要理解两点:
1.公平锁与非公平锁的区别
FairSync中整个tryAcquire()代码只比nonfairTryAcquire()方法多了这么一行!!!
主要判断:是否有其它线程在队列的最前面。
以此来保证有序性,也就是先来后到!
这就是公平!
而不公平就是可以插队拿到锁!
2.重入锁的实现原理
1. 在线程获取锁的时候,如果已经获取锁的线程是当前线程的话则直接再次获取成功;
2. 由于锁会被获取n次,那么只有锁在被释放同样的n次之后,该锁才算是完全释放成功
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();//获取当前线程实例
int c = getState();//获取state变量的值,即当前锁被重入的次数
if (c == 0) { //state为0,说明当前锁未被任何线程持有
if (compareAndSetState(0, acquires)) { //以cas方式获取锁
setExclusiveOwnerThread(current); //将当前线程标记为持有锁的线程
return true;//获取锁成功,非重入
}
}
else if (current == getExclusiveOwnerThread()) { //当前线程就是持有锁的线程,说明该锁被重入了
int nextc = c + acquires;//计算state变量要更新的值
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);//非同步方式更新state值
return true; //获取锁成功,重入
}
return false; //走到这里说明尝试获取锁失败
}