ReetrantLock锁的初步介绍
public ReentrantLock() { //默认new一个ReentrantLock是创建一个非公平锁
sync = new NonfairSync();
}
lock方法
public void lock() {
sync.lock();//默认是个非公平锁
}
sync.lock方法是NonfairSync静态内部类的lock方法
static final class NonfairSync extends Sync { //Sync继承了AbstractQueuedSynchronizer(后面要说的AQS)
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
//AbstractQueuedSynchronizer.compareAndSetState方法,实际上是调用unsafe类的方法
//unsafe.compareAndSwapInt(this, stateOffset, expect, update);这里使用cas来修改stateOffset锁偏移量参数值
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//获取锁
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
acquire–>AbstractQueuedSynchronizer.acquire
public final void acquire(int arg) {
/***
**tryAcquire方式就是上面NonfairSync类具体的实现
**addWaiter增加等待队列
**
**/
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
nonfairTryAcquire方法
final boolean nonfairTryAcquire(int acquires) {//尝试获取锁
final Thread current = Thread.currentThread();//获取当前线程
int c = getState();//AbstractQueuedSynchronizer.state当前状态
if (c == 0) {//如果状态为0,则处于一种无锁的状态
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);//然后将AbstractQueuedSynchronizer要执行的线程设置成当前线程
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;
}
acquireQueued,获取线程队列
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {//如果是第一个线程,则会再次尝试去获取锁
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
//如果队列获取失败,则取消获取,并释放锁
if (failed)
cancelAcquire(node);
}
}
shouldParkAfterFailedAcquire
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
如果这个节点已经准备去请求设置一个发布的状态信号,以致它可以安全的上锁
*/
return true;
if (ws > 0) {
/*当ws>0,前一个线程被取消则跳过前置任务和指示重试。
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
//当=0或者-3的时候,说明当前该线程是处于一种释放锁的状态,则上面的while结束循环
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//这里又用到了CAS技术,这里后面在分析
}
return false;
}
parkAndCheckInterrupt
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);//这里类似线程wait
return Thread.interrupted();
}
总结:ReentrantLock使用的是cas技术+等待队列来实现+LockSupport该类是实现,所谓的AQS就是指AbstractQueuedSynchronizer(抽象同步队列)。说白了ReentrantLock就是AQS的一种实现。尝试的去获取锁,也就是线程状态(根据线程的定义状态的去是比较替换来实现,cas(compareAndSwap)是重点)
CAS
CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术。简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替换当前变量的值。
cas技术主要实现基础类UnSafe,也有很多基于Unsafe的实现类在java.concurrent.atomic包下的一些类的compareAndSet的是实现;例如AtomicInteger
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
UnSafe调用的native的修饰的方法也就是虚拟机C++的实现
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
基于openjdk1.8是分析compareAndSwapInt的本地方法实现,找到对应的unsafe.cpp(这里为什么我可以断定的是unsafe.cpp文件呢?不妨可以先初步了解一下jni,看个小demo就可以了https://www.cnblogs.com/dengpeng1004/p/8745186.html)
unsafe.cpp中compareAndSwapInt的实现
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
UnsafeWrapper("Unsafe_CompareAndSwapInt");//这句代码实际上的实现没有多大意义,可以忽略
oop p = JNIHandles::resolve(obj);//这里将obj句柄解析到oop中。JNIHandles::resolve在jniHandles.hpp找到
jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;//这句代码才是关键
UNSAFE_END
jniHandles::resolve
// Resolve handle into oop
inline static oop resolve(jobject handle);
index_oop_from_field_offset_long是在jvm.cpp中,这里是做了内存地址偏移(这里不知道怎么去表达,麻烦各路大佬可以帮忙解答一下)
static inline void* index_oop_from_field_offset_long(oop p, jlong field_offset) {
assert_field_offset_sane(p, field_offset);
jlong byte_offset = field_offset_to_byte_offset(field_offset);
if (sizeof(char*) == sizeof(jint)) { // (this constant folds!)
return (address)p + (jint) byte_offset;
} else {
return (address)p + byte_offset;
}
}
Atomic::cmpxchg(x, addr, e),在atomic.cpp中,最终会根据具体的宿主环境内联具体的实现,具体我们参照include的atomic.inline.hpp头文件
// Performs atomic compare of *dest and compare_value, and exchanges *dest with exchange_value
// if the comparison succeeded. Returns prior value of *dest. Guarantees a two-way memory
// barrier across the cmpxchg. I.e., it's really a 'fence_cmpxchg_acquire'.
inline static jint cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value);
atomic.inline.hpp
//这里我的理解是,会调用对应的平台方法的实现
#ifndef SHARE_VM_RUNTIME_ATOMIC_INLINE_HPP
#define SHARE_VM_RUNTIME_ATOMIC_INLINE_HPP
#include "runtime/atomic.hpp"
// Linux
#ifdef TARGET_OS_ARCH_linux_x86
# include "atomic_linux_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_sparc
# include "atomic_linux_sparc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_zero
# include "atomic_linux_zero.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_arm
# include "atomic_linux_arm.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_ppc
# include "atomic_linux_ppc.inline.hpp"
#endif
// Solaris
#ifdef TARGET_OS_ARCH_solaris_x86
# include "atomic_solaris_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_solaris_sparc
# include "atomic_solaris_sparc.inline.hpp"
#endif
// Windows
#ifdef TARGET_OS_ARCH_windows_x86
# include "atomic_windows_x86.inline.hpp"
#endif
// AIX
#ifdef TARGET_OS_ARCH_aix_ppc
# include "atomic_aix_ppc.inline.hpp"
#endif
// BSD
#ifdef TARGET_OS_ARCH_bsd_x86
# include "atomic_bsd_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_bsd_zero
# include "atomic_bsd_zero.inline.hpp"
#endif
#endif // SHARE_VM_RUNTIME_ATOMIC_INLINE_HPP
atomic_linux_x86.inline.hpp简单的已这个linux_x86这个系统平台的实现来讲:
inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value) {
//主要是执行cmpxchgq汇编指令来操作内存
bool mp = os::is_MP();
__asm__ __volatile__ (LOCK_IF_MP(%4) "cmpxchgq %1,(%3)"
: "=a" (exchange_value)
: "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
: "cc", "memory");
return exchange_value;
}
LOCK_IF_MP
#define LOCK_IF_MP(mp) "cmp $0, " #mp "; je 1f; lock; 1: "//这里会有加锁的操作
is_MP
static inline bool is_MP() {//返回处理器的个数
// During bootstrap if _processor_count is not yet initialized
// we claim to be MP as that is safest. If any platform has a
// stub generator that might be triggered in this phase and for
// which being declared MP when in fact not, is a problem - then
// the bootstrap routine for the stub generator needs to check
// the processor count directly and leave the bootstrap routine
// in place until called after initialization has ocurred.
return (_processor_count != 1) || AssumeMP;
}
链接: https://pan.baidu.com/s/166T7qA6YDmUo4uuzFmOcjQ 提取码: 57dj;有openjdk1.8的源码