ReentrantLock之Lock方法
程序员文章站
2022-05-05 10:00:13
...
ReentranLock JDK 1.8 类源码如下:
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
...
abstract static class Sync extends AbstractQueuedSynchronizer {
...
...
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock();
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
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;
}
...
}
...
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
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;
}
}
...
}
公平锁和非公平锁都调用了acquire(1);方法,此方法如下:
tryAcquire方法如下:如果state状态为0,则获取锁成功,否则(红色框里是重入获取锁的实现,可见是)判断当前线程是否为已获得锁的线程,如果是,则state加1,否则获取失败。
补充:getState是Sync 的父类AbstractQueuedSynchronizer的方法,读者可阅读此源码进一步研究。
compareAndSetState(0, 1): CAS 原子性设置(由硬件保证,cpu执行汇编)setExclusiveOwnerThread(Thread.currentThread()) : 设置exclusiveOwnerThread变量/**
* The current owner of exclusive mode synchronization.
*/
private transient Thread exclusiveOwnerThread;
标记当前获取锁的线程信息。
acquire中调用了addWaiter,此方法如下:
可见是将当前线程加入阻塞队列中
所以acquire方法总体执行的是,判断锁的state是否为0,如果是则加锁成功state为1,将当前获取锁的线程标记,否则判断当前获取锁的线程是否为已拿到锁的线程,如果是,state+1 获取锁成功(可重入性);否则,失败,将自己放入队列中(尾插法),执行selfInterrupt();优雅中断(阻塞)。
/**
* Convenience method to interrupt current thread.
*/
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
再来看看公平锁和非公平锁的不同:
从源码看,两者在lock中不同在于acquire方法tryAcquire的实现
看源码可知公平锁的实现中多了红框的内容:
此端代码是判断当前线程是否为列队头中的线程。。。在阻塞的线程中只有头线程才能获取成功锁
上一篇: 数据结构-队列
下一篇: Java AQS初步介绍
推荐阅读
-
asp.net基础学习之控件的使用方法
-
Android笔记之:在ScrollView中嵌套ListView的方法
-
Android控件系列之Shape使用方法
-
Android开发笔记之:在ImageView上绘制圆环的实现方法
-
android UI进阶之android中隐藏的layout 抽屉的使用方法
-
Android开发笔记之:如何安全中止一个自定义线程Thread的方法
-
Android编程开发之打开文件的Intent及使用方法
-
Laravel学习笔记之Artisan命令生成自定义模板的方法
-
详解Jquery 遍历数组之$().each方法与$.each()方法介绍
-
python学习之第三方包安装方法(两种方法)