AQS简述

AQS原理简述

AQS衍生了三个问题:

1.同步状态的操作

2.阻塞/唤醒线程

3.线程等待队列

同步状态

//同步状态
private volatile int state;

protected final int getState() {
  		return state;
 }

protected final void setState(int newState) {
  		state = newState;
}
//CAS操作来更改当前线程状态
protected final boolean compareAndSetState(int expect, int update) {
      // See below for intrinsics setup to support this
      return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

AQS中包含了一个Node队列 在这个队列中定义了线程的各种状态

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;//Condition专用 表示节点在Condition队列中,因为某个条件而被阻塞

  			static final int PROPAGATE = -3;//传播 适用于共享模式

        volatile int waitStatus;//后续节点的状态

        volatile Node prev;//前驱

        volatile Node next;//后驱
  
        volatile Thread thread;//当前节点的线程

        Node nextWaiter;//Condition队列使用

        final boolean isShared() {//判断当前节点是否为共享模式
            return nextWaiter == SHARED;
        }

        final Node predecessor() throws NullPointerException {//获取后驱节点 当后驱节点没有会返回空指针
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

将节点插入队列的方法如下:

private Node enq(final Node node) {
        for (;;) {//自旋操作 
          //第一次获取尾部节点 可能出现两种情况 当前队列为空 所以进if 创建一个空的node节点 作为尾部节点和头部节点
          //第二种情况和第二次在进入一样 在获取尾部节点 这时候进入else 把当前传入的节点的前驱设置当前的尾部节点 在通过CAS操作 
            Node t = tail;//获取队列尾部节点
            if (t == null) { // 当尾部节点为空的时候 说明当前是第一个节点
                if (compareAndSetHead(new Node()))//通过CAS操作添加一个头部节点
                    tail = head;//尾部节点复制给头部
            } else {
                node.prev = t;//当前尾部节点为传入节点的前驱
                if (compareAndSetTail(t, node)) {//直到CAS成功为止
                    t.next = node;//添加当前节点为后驱节点
                    return t;//返回当前尾部节点
                }
            }
        }
    }
### Java AQS (AbstractQueuedSynchronizer) 使用指南 #### AQS简介 AQSJava 并发包中的核心组件之一,提供了一种用来构建锁和其他同步器的基础框架。该类位于 `java.util.concurrent.locks` 包下,并且实现了 FIFO 队列来管理线程等待队列[^1]。 #### 继承结构 AQS 和 AQLS (AbstractQueuedLongSynchronizer)都继承了名为 AOS(AbstractOwnableSynchronizer)的一个抽象类。此父类引入于 JDK 1.6 版本中,主要用于表示锁与其拥有者间的关系,在独占模式下调用方可以设置当前占有锁的对象实例。 #### 设计灵活性 为了适应不同的应用场景需求,AQS 提供了一系列模板方法让开发者能够方便地创建自定义同步工具。这些方法包括但不限于: - **tryAcquire(int arg)**:尝试获取独占式的资源; - **tryRelease(int arg)** :尝试释放已持有的独占式资源; - **tryAcquireShared(int arg)** : 尝试获得共享类型的许可; - **tryReleaseShared(int arg)** : 放弃之前得到过的共享权限; 上述四个函数都需要由具体的子类去重写实现,从而定义各自独特的同步机制[^3]。 #### 实际应用案例 - CountDownLatch 作为 AQS 应用的经典范例之一,`CountDownLatch` 展现了如何利用 AQS 来处理多线程间的协作问题。此类允许一个或多个线程一直阻塞直到其他一些线程完成一系列操作之后再继续执行下去。下面给出一段简单的代码片段展示其基本用法: ```java import java.util.concurrent.CountDownLatch; public class Worker implements Runnable { private final CountDownLatch startSignal; private final CountDownLatch doneSignal; public Worker(CountDownLatch startSignal, CountDownLatch doneSignal){ this.startSignal = startSignal; this.doneSignal = doneSignal; } @Override public void run(){ try{ System.out.println(Thread.currentThread().getName()+" is waiting"); startSignal.await(); // wait until all threads are ready. doWork(); System.out.println(Thread.currentThread().getName()+" has finished work."); doneSignal.countDown();// signal that the current thread has completed its task. }catch(Exception e){ throw new RuntimeException(e); } } protected void doWork(){} } // Usage example: int nThreads = 5; CountDownLatch startGate = new CountDownLatch(nThreads); CountDownLatch endGate = new CountDownLatch(nThreads); for(int i=0;i<nThreads;++i){ Thread t=new Thread(new Worker(startGate,endGate),"Worker-"+i); t.start(); } startGate.countDown(); // release all workers at once endGate.await(); // main waits here for them to finish their jobs System.out.println("All tasks have been processed!"); ``` 这段程序展示了五个工作线程在接收到启动信号前处于挂起状态,当最后一个工作者准备好后它们会同时开始运行各自的作业并最终通知主线程所有任务已完成[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值