8.2 AQS 原理
特点
1. 用 state 属性来表示资源的状态(分独占模式和共享模式),控制如何获取锁和释放锁
getState - 获取 state 状态
setState - 设置 state 状态
compareAndSetState - cas 机制设置 state 状态
独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源
2. 提供了基于 FIFO 的等待队列,类似于 Monitor 的 EntryList
3. 条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的 WaitSet
自定义锁 - 不可重入锁
测试一
package com.rui.eight;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* 测试
*/
@Slf4j(topic = "c.Test13")
public class Test13 {
public static void main(String[] args) {
MyLock lock = new MyLock();
new Thread(() -> {
log.debug("t1 begin...");
lock.lock();
try {
log.debug("t1 lock...");
} finally {
log.debug("t1 unlock...");
lock.unlock();
}
}, "t1").start();
new Thread(() -> {
log.debug("t2 begin...");
lock.lock();
try {
log.debug("t2 lock...");
} finally {
log.debug("t2 unlock...");
lock.unlock();
}
}, "t2").start();
}
}
/**
* 自定义锁 - 不可重入锁
*/
class MyLock implements Lock {
/**
* 独占锁
*/
class MySync extends AbstractQueuedSynchronizer {
/**
* 获取锁
*/
@Override
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0, 1)) {
// 加锁成功,设置 owner 为当前线程
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
/**
* 释放锁
*/
@Override
protected boolean tryRelease(int arg) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
/**
* 是否拥有锁
*/
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
protected Condition newConditon() {
return new ConditionObject();
}
}
private MySync sync = new MySync();
/**
* 获取锁
*/
@Override
public void lock() {
sync.acquire(1);
}
/**
* 获取锁,可被打断
*/
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
* 尝试获取锁
*/
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
/**
* 尝试获取锁,超时时间
*/
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
/**
* 释放锁
*/
@Override
public void unlock() {
sync.release(1);
}
/**
* 条件变量
*/
@Override
public Condition newCondition() {
return sync.newConditon();
}
}
// 某次运行结果
14:58:56 [t2] c.Test13 - t2 begin...
14:58:56 [t1] c.Test13 - t1 begin...
14:58:56 [t2] c.Test13 - t2 lock...
14:58:56 [t2] c.Test13 - t2 unlock...
14:58:56 [t1] c.Test13 - t1 lock...
14:58:56 [t1] c.Test13 - t1 unlock...
进程已结束,退出代码 0
测试二
package com.rui.eight;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* 测试
*/
@Slf4j(topic = "c.Test13")
public class Test13 {
public static void main(String[] args) {
MyLock lock = new MyLock();
new Thread(() -> {
log.debug("t1 begin...");
lock.lock();
log.debug("t1 lock...");
lock.lock();
log.debug("t1 relock...");
try {
log.debug("t1");
} finally {
log.debug("t1 unlock...");
lock.unlock();
}
}, "t1").start();
}
}
/**
* 自定义锁 - 不可重入锁
*/
class MyLock implements Lock {
/**
* 独占锁
*/
class MySync extends AbstractQueuedSynchronizer {
/**
* 获取锁
*/
@Override
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0, 1)) {
// 加锁成功,设置 owner 为当前线程
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
/**
* 释放锁
*/
@Override
protected boolean tryRelease(int arg) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
/**
* 是否拥有锁
*/
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
protected Condition newConditon() {
return new ConditionObject();
}
}
private MySync sync = new MySync();
/**
* 获取锁
*/
@Override
public void lock() {
sync.acquire(1);
}
/**
* 获取锁,可被打断
*/
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
* 尝试获取锁
*/
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
/**
* 尝试获取锁,超时时间
*/
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
/**
* 释放锁
*/
@Override
public void unlock() {
sync.release(1);
}
/**
* 条件变量
*/
@Override
public Condition newCondition() {
return sync.newConditon();
}
}
// 某次运行结果
15:02:01 [t1] c.Test13 - t1 begin...
15:02:01 [t1] c.Test13 - t1 lock...
8.3 ReentrantLock 原理
8.3.1 非公平锁(NonfairSync)实现原理
加锁解锁流程
1. Thread-0 获取锁
第一步,执行 compareAndSetState(0, 1)
将锁状态由 0 修改为 1,compareAndSetState(0, 1) 返回结果为 true,表明 Thread-0 获取锁成功
第二步,执行 setExclusiveOwnerThread(Thread.currentThread())
设置 Owner 为 Thread-0
2. Thread-1 获取锁
第一步, 执行 compareAndSetState(0, 1)
因为此时 state 的值为 1,所以 compareAndSetState(0, 1) 返回结果为 false,表明 Thread-1 获取锁失败
第二步,执行 acquire(1)
第 1 步,执行 !tryAcquire(arg)
Thread-1 再次获取锁,因为 Thread-0 未释放锁,所以 !tryAcquire(arg) 返回结果为 true,表明 Thread-1 再次获取锁失败
第 2 步,执行 addWaiter(Node.EXCLUSIVE)
addWaiter 方法的作用是构造 Node 队列并为当前线程创建节点并将其排入队列
Node 队列,即等待队列(类似于 Monitor 的 EntryList),双端队列
Node 队列的创建是懒惰的,hand 是队列的头部,tail 是队列的尾部
Node 队列被创建时,addWaiter 方法会创建两个节点
第一个 Node 节点称为 Dummy(哑元)或哨兵,用来占位,并不关联线程
第二个 Node 节点关联当前线程
图中黄色三角表示该 Node 节点的 waitStatus(状态)
Node.EXCLUSIVE 表示独占,Node.SHARED 表示共享
第 3 步,执行 acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
第 ① 步,执行 p == head
p 为 node.predecessor(),即关联当前线程的 Node 节点的前驱节点
因为关联 Thread-1 的 Node 节点的前驱节点为 Dummy,且 Dummy 是队列的头部,所以 p == head 的返回结果为 true
第 ② 步,执行 tryAcquire(arg)
Thread-1 再次获取锁,因为 Thread-0 未释放锁,所以 tryAcquire(arg) 返回结果为 false,表明 Thread-1 获取锁失败
第 ③ 步,执行 shouldParkAfterFailedAcquire(p, node)
检查 p 的 waitStatus,若为 -1,则返回 true;若为 0,则修改为 -1 并返回 false
因为此时 Dummy 的 waitStatus 为 0,所以 shouldParkAfterFailedAcquire(p, node) 返回结果为 false
回到 for 循环初始,待再次执行到第 ③步
因为此时 Dummy 的 waitStatus 为 -1,所以 shouldParkAfterFailedAcquire(p, node) 返回结果为 true
第 ④ 步,执行 parkAndCheckInterrupt()
阻塞
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
3. Thread-2、Thread-3 获取锁
4. Thread-0 释放锁
第一步,执行 tryRelease(arg)
设置 Owner 为 null,并将锁状态由 1 修改为 0
tryRelease(arg) 返回结果为 true
【不公平的体现】
第二步,执行 h != null
h 为 head
检查 Node 队列是否为空
因为此时 head 为 Dummy,所以 h != null 返回结果为 true
第三步,执行 h.waitStatus != 0
因为此时 Dummy 的 waitStatus 为 -1,所以 h.waitStatus != 0 返回结果为 true
第四步,执行 unparkSuccessor(h)
唤醒 h 的后继结点(如果存在)
Thread-1 被唤醒
第五步,执行 p == head
p 为 Dummy
因为 Dummy 是队列的头部,所以 p == head 的返回结果为 true
第六步,执行 tryAcquire(arg)
Thread-1 第五次获取锁,因为 Thread-0 已释放锁,所以 tryAcquire(arg) 返回结果为 true,表明 Thread-1 获取锁成功
将锁状态由 0 修改为 1,并设置 Owner 为 Thread-1
将关联 Thread-1 的 Node 节点设置为 Node 队列的头部,并将该节点关联的线程设置为 null
5. 不公平的体现
Thread-4 获取锁
【接第一步】
第二步, 执行 compareAndSetState(0, 1)
将锁状态由 0 修改为 1,compareAndSetState(0, 1) 返回结果为 true,表明 Thread-4 获取锁成功
第二步,执行 setExclusiveOwnerThread(Thread.currentThread())
设置 Owner 为 Thread-4
[Thread-1 流程略]
并发编程就更到这了,P241
说些废话
本篇文章为博主日常学习记录,故而会概率性地存在各种错误,若您在浏览过程中发现一些,请在评论区指正,望我们共同进步,谢谢!