// ----------------- 悲观锁 -------------------------
synchronized (MUTEX) {
// 同步代码块
}
ReentrantLock lock = new ReentrantLock();
lock.lock();
// 同步代码块
lock.unlock();
// ----------------- 乐观锁 -------------------------
AtomicInteger atomicInteger = new AtomicInteger(0);
atomicInteger.incrementAndGet();
// 悲观锁的实现方式很直观,先进行加锁,然后访问互斥资源,最后释放锁;那么乐观锁时如何实现的呢?我们通过介绍乐观锁主要的实现方式 CAS 来为大家解惑。
// 这里简单给大家回顾一下 CAS ,有需要了解更多的读者请去阅读 CAS 章节。
CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的同步。
CAS算法涉及到三个操作数:当前内存值 V、原始值 A、要写入的新值 B。
当且仅当 V 的值等于 A 时,CAS通过原子方式用新值B来更新V的值("比较+更新"整体是一个原子操作),否则不会执行任何操作。
// atomicInteger.incrementAndGet() 使用上述方式实现:
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
// v 表示获取到的内存中的当前值
v = getIntVolatile(o, offset);
// compareAndSwapInt() 是一个原子操作、进行比较更新
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}
final void lock() {
acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
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;
}
}
// 判断当前线程是否位于同步队列中的第一个。如果是则返回true,否则返回false。
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
// 读锁
ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
// 写锁
ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
// 读锁 公平锁
public void lock() {
sync.acquireShared(1);
}
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0) doAcquireShared(arg);
}
protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
* 1. If write lock held by another thread, fail.
* 2. Otherwise, this thread is eligible for
* lock wrt state, so ask if it should block
* because of queue policy. If not, try
* to grant by CASing state and updating count.
* Note that step does not check for reentrant
* acquires, which is postponed to full version
* to avoid having to check hold count in
* the more typical non-reentrant case.
* 3. If step 2 fails either because thread
* apparently not eligible or CAS fails or count
* saturated, chain to version with full retry loop.
*/
Thread current = Thread.currentThread();
int c = getState();
// 存在写锁且不是当前线程
if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return -1;
// 当前线程持有写锁或仅有读锁或无锁
int r = sharedCount(c);
if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) {
// 如果是第一次获取 初始化 firstReader、firstReaderHoldCount 不是第一次获取 对 readHolds 对应线程计数+1
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0) readHolds.set(rh);
rh.count++;
}
return 1;
}
return fullTryAcquireShared(current);
}
final int fullTryAcquireShared(Thread current) {
/*
* This code is in part redundant with that in
* tryAcquireShared but is simpler overall by not
* complicating tryAcquireShared with interactions between
* retries and lazily reading hold counts.
*/
HoldCounter rh = null;
// 自旋 不挂起线程
for (; ; ) {
int c = getState();
if (exclusiveCount(c) != 0) {
// 非当前线程获取到写锁获取失败
if (getExclusiveOwnerThread() != current)
return -1;
// else we hold the exclusive lock; blocking here
// would cause deadlock.
} else if (readerShouldBlock()) {
// 走到这里说明没有写锁被占有 判断是否存在重入
// Make sure we're not acquiring read lock reentrantly
// 当前线程为 firstReader 走下面 CAS
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
// cachedHoldCounter 没有缓存或缓存的不是当前线程
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
// 说明上一行是初始化 移除上面产生的初始化
if (rh.count == 0)
readHolds.remove();
}
}
if (rh.count == 0)
return -1;
}
}
// 是否已经达到读锁获取次数上限
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// CAS 获取锁
if (compareAndSetState(c, c + SHARED_UNIT)) {
// 读锁初始化和计数
if (sharedCount(c) == 0) {
// 第一次添加读锁
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
// firstReader 为当前线程
firstReaderHoldCount++;
} else {
// 否则更新 readHolds 对应线程读锁计数
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
cachedHoldCounter = rh; // cache for release
}
return 1;
}
}
}
// 无法获取读锁,将获取读锁线程放入等待队列中
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (; ; ) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted) selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true;
}
} finally {
if (failed) cancelAcquire(node);
}
}
// 写锁 公平锁
public void lock() {
sync.acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
* 1. If read count nonzero or write count nonzero
* and owner is a different thread, fail.
* 2. If count would saturate, fail. (This can only
* happen if count is already nonzero.)
* 3. Otherwise, this thread is eligible for lock if
* it is either a reentrant acquire or
* queue policy allows it. If so, update state
* and set owner.
*/
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
// 存在读锁或写锁
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
// 存在读锁或存在写锁但不是当前线程持有获取失败
if (w == 0 || current != getExclusiveOwnerThread()) return false;
// 获取锁是否超过上限
if (w + exclusiveCount(acquires) > MAX_COUNT) throw new Error("Maximum lock count exceeded");
// Reentrant acquire
// 走到这里说明当前线程持有写锁 重入
setState(c + acquires);
return true;
}
// 不存在锁 判断队列阻塞策略 并进行 CAS 尝试获取锁
if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) return false;
setExclusiveOwnerThread(current);
return true;
}