JAVA-AQS-ConditionObject 笔记

80 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情

AQS-ConditionObject

ConditionObject是AQS中另一个用于控制线程的子类,在AQS子类Sync中使用到,Condition的目的是替代Object的wait,notify,notifyAll方法,ConditionObject为Condition接口实现。

整体结构

classDiagram
  class Sync {
    //状态标识
    -state : int;
	//头节点
    -head : Node;
    //尾节点
    -tail : Node;
    //当前运行线程
    -exclusiveOwnerThread : Thread
  }
  class Node{
	//前一个节点
    -prev : Node;
	//后一个节点
    -next : Node;
	//运行线程
    -thread : Thread;
	//下一个等待节点
    -nextWaiter Node;
  }
  class ConditionObject{
  	//头等待节点
    -firstWaiter Node;
  	//尾等待节点
    -lastWaiter Node;
  }
  Node  --* Sync  : 持有
  Node  --* ConditionObject  : 持有
  Node  --< Node  : 链表



Sync继承AbstractQueuedSynchronizer,是基于AQS的同步控制,为锁的基础实现。

ConditionObject持有的节点会加入Node的nextWaiter节点中。

使用时序图

sequenceDiagram
    participant 线程A
    participant 线程B
    participant Sync
    participant ConditionObject
    
    线程A->>Sync: lock(),当前线程对应头节点
    线程A->>ConditionObject: await()新建节点添加至等待队列队尾,停止当前线程
    线程B->>Sync: lock(),当前线程对应头节点
    线程B->>ConditionObject: signal(),释放资源
    ConditionObject-->>Sync: transferForSignal转换等待队列头节点至AQS队尾
    线程B->>Sync: unlock(),释放资源
	线程A->>Sync: unlock(),释放资源

关键方法

阻塞线程:await

对应Object.wait(),通过AQS机制释放锁定的资源,终止当前线程,恢复后使用AQS独占模式重新锁定资源

acquireQueued:此时node节点已转换为AQS中节点

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();
    long savedState = fullyRelease(node);
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {
        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);
}

唤醒线程:signal

transferForSignal转换节点后await()中acquireQueued(node,savedState)操作的节点已是AQS中的节点

isHeldExclusively:子类实现.判断是否独家持有

public final void signal() {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);
}

实例

@Slf4j
public class LockConditionDemo {
    /**
     * 非公平锁,都可争夺
     */
    public static final ReentrantLock lock = new ReentrantLock();

    public static final Condition condition = lock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        log.info("主程序开始");
        ConditionDemoThread conditionDemoThread = new ConditionDemoThread();
        conditionDemoThread.start();
        Thread.sleep(1000);
        LockConditionDemo.lock.lock();
        log.info("主程序lock");
        try{
            log.info("主程序释放-Condition.signal()");
            LockConditionDemo.condition.signal();
            Thread.sleep(1000);
            log.info("主程序释放完成");
        }finally {
            LockConditionDemo.lock.unlock();
        }
        log.info("主程序unlock");
    }
}

@Slf4j
class ConditionDemoThread extends Thread{
    @Override
    public void run() {
        LockConditionDemo.lock.lock();
        log.info("线程lock ");
        try{
            log.info("线程开始等待-Condition.await()");
            LockConditionDemo.condition.await();
            log.info("线程恢复");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            LockConditionDemo.lock.unlock();
            log.info("线程unlock ");
        }
        try {
            Thread.sleep(1000);
            log.info("线程结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}