java并发编程之美 学习笔记
AbstractQueuedSynchronizer
AbstractQueuedSynchronizer简称AQS
,它是实现同步器的基础组件(如:ReentrantLock,Semaphore,CountDownLatch
)。
AQS
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
/*
* +------+ prev +-----+ +-----+
* head | | <---- | | <---- | | tail
* +------+ +-----+ +-----+
*
**/
private transient volatile Node head;
private transient volatile Node tail;
private volatile int state;
}
- AQS是一个FIFO的双向队列,内部通过
head
和tail
记录队首和队尾元素,元素类型为Node
. state
(后续会详细讲解):- 对于
ReentrantLock
: 表示当前线程获取锁的可重入次数; - 对于
ReentrantReadWriteLock
:- 高16为,表示获取该读锁的次数
- 低16位,表示获取写锁线程可重入次数;
- 对于
Semaphore
: 表示可用信号的个数 - 对于
CountDownLatch
:表示计数器当前值;
- 对于
Node
Node 中的 thread 变量用来存放进入 AQS队列里面的线程.
static final class Node {
//共享模式,
static final Node SHARED = new Node();
//独占模式
static final Node EXCLUSIVE = null;
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
/**
* CANCELLED == 1 , thread被取消;
* SIGNAL == -1 , thread需要被唤醒
* CONDITION == -2, thread在condition队列中;
* PROPAGATE == -3, 释放共享资源时,需要通知其他节点
* 0, 表示当前节点在sync队列中,等待着获取锁。
*/
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
//存储condition队列中的后继节点。
Node nextWaiter;
final boolean isShared() {
return nextWaiter == SHARED;
}
}
ConditionObject
AQS有个内部类 ConditionObject,用来结合锁实现线程同步 。
ConditionObject是条件变量,每个条件变量对应一个条件队列(单向链表队列),其用来存放调用条件变量的await()方法后被阻塞的线程.
对于AQS来说,线程同步的关键是对状态state进行操作。根据state是否属于一个线程,操作state的方式分为独占和共享两种方式;
//独占锁获取&释放
public final void acquire(int arg) {}
public final void acquireInterruptibly(int arg){}
public final boolean tryAcquireNanos(int arg, long nanosTimeout){}
public final boolean release(int arg) {}
//共享锁获取&释放
public final void acquireShared(int arg) {}
public final void acquireSharedInterruptibly(int arg){}
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout){}
public final boolean releaseShared(int arg) {}
独占锁
获取锁
获取锁,在writeLock.lock()内部逻辑中调用;
/*
* +------+ prev +-----+ +-----+
* head | | <---- | | <---- | | tail
* +------+ +-----+ +-----+
*
**/
private transient volatile Node head;
private transient volatile Node tail;
private volatile int state;
//获取锁,在writeLock.lock()内部逻辑中调用;
public final void acquire(int arg) {
//1.首先尝试获取资源,当获取失败时进行2, 若获取成功则直接跳出
//1.由子类实现,模板方法
if (!tryAcquire(arg) && // 1
acquireQueued(
addWaiter(Node.EXCLUSIVE) // 2 ,此时的mode为独占模式
, arg) //3 调用LockSupport.park(this); 挂起当前线程;
)
//中断当前线程..
selfInterrupt();
}
//2.
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
if (pred != null) {
//当pred不为空时,同enq中 else{}部分代码,
//将node.prev指向tail(这里是pred),然后将自身设置为tail
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//2.1 当tail为null,或者compareAndSetTail(pred,node)失败时,调用enq入列;
enq(node);
return node;
}
//2.1
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) {
// 初始化,设置一个“哨兵” Heder
if (compareAndSetHead(new Node()))
tail = head; //初始化成功时,tail也指向“哨兵”
} else {
//将node.prev指向tail, 然后将自身设置为tail
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
释放锁
释放锁,如在 writeLock.unlock()中调用;
public final boolean release(int arg) {
//1.如果tryRelease成功进行释放锁操作
//由子类实现...
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//2.
unparkSuccessor(h);
return true;
}
return false;
}
//2.从后续的thread中,找出一个然后执行LockSupport.unpark();
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
//将当前node
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
例:代码跟踪
public class MultiLockTest {
private ReentrantLock lock = new ReentrantLock();
public void write(String msg){
lock.lock();
System.out.println(LocalDateTime.now()+" ["+Thread.currentThread().getName()+"] write() : "+msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
}
public static void main(String[] args) throws InterruptedException {
MultiLockTest app = new MultiLockTest();
Thread thread1 = new Thread(() -> {
app.write("111");
},"thread1");
Thread thread2 = new Thread(() -> {
app.write("222");
},"thread2");
thread1.start();
Thread.sleep(10);
thread2.start();
}
}
共享锁(略)
后续讲读写锁时再详细分析.
条件变量的支持
例
public class LockConditionTest {
ReentrantLock lock = new ReentrantLock();
Condition notEmptyCondition = lock.newCondition();
Queue queue = new ArrayDeque(10);
public void consume() {
lock.lock();
while (queue.isEmpty()) {
try {
System.out.println("consume队列为空,阻塞....");
//queue为空,阻塞等待
notEmptyCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费了:" + queue.poll());
lock.unlock();
}
public void product(Object obj) {
lock.lock();
queue.add(obj);
System.out.println("生产了:" + obj);
notEmptyCondition.signal();
lock.unlock();
}
}
上述代码作用等同于:
public synchronized void consume2() {
while (queue.isEmpty()) {
wait();
}
//cosume sth
}
public synchronized void product2(Object obj) {
//product sth
notify();
}
lock.lock()
相当于进入了synchronized{ }
代码块lock.unlock()
相当有退出了synchronized块lock.newCondition()
创建了一个AbstractQueuedSynchronizer.ConditionObject
对象condition.await()
相当于调用了object.wait()
condition.signal()
相当于调用了object.notify()
;condition.signalAll()
相当于调用了object.notifyall()
;
ConditionObject
public class ConditionObject implements Condition, java.io.Serializable {
//condition自身持有的单向列表
private transient Node firstWaiter;
private transient Node lastWaiter;
}
await()
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//1.添加thread到condition等待列表;
Node node = addConditionWaiter();
//2.释放当前线程获取的锁---更新state状态为0,此时锁可由其他线程获取
int savedState = fullyRelease(node);
int interruptMode = 0;
//3. 当node.waitStatus == Node.CONDITION 时,返回false;
while (!isOnSyncQueue(node)) {
//调用park方法挂起当前线程 -----
//直到当前线程被别的线程signale唤醒 ---- 执行后续的逻辑
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 重新尝试获取锁,执行后续的逻辑
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
//1.
private Node addConditionWaiter() {
Node t = lastWaiter;
//如果lastWaiter状态为CANCELLED ,从队列中清除;
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
//将当前线程 加入condition的等待队列中....
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
//更新当前condition等待列表的lastWaiter为当前node;
lastWaiter = node;
return node;
}
//2.
final int fullyRelease(Node node) {
boolean failed = true;
try {
int savedState = getState();
//释放锁 --- 更新state状态..
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
signal()
public final void signal() {
//isHeldExclusively() 由子类实现..
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
//1.激活condition等待队列的firstwatier激活
doSignal(first);
}
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) && //2.
(first = firstWaiter) != null);
}
//2 调用了AbstractQueuedSynchronizer.transferForSignal()
方法
//2.
final boolean transferForSignal(Node node) {
//将node的waitstaus更新为 0
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
//将condition队列中的节点 传输到aqs的等待队列中 ---在未来的时刻等待时机获取锁.
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
//调用LockSupport.unpark 激活thread
LockSupport.unpark(node.thread);
return true;
}
代码跟踪
public void testTrace(){
Thread thread1 = new Thread(() -> {
tool.consume();
},"consumer_thread");
thread1.start();
Thread.sleep(10);
tool.product("xx");
}