并发编程之AQS详解

AQS(AbstractQueuedSynchronizer)介绍

  • 抽象队列同步器AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的基础框架,AQS的设计是基于模板方法模式的,也就是说,使用者需要继承同步器并重写指定的方法。

接下来先看下关键源码

public abstract class AbstractQueuedSynchronizer {
    
    private transient volatile Node head;
    
    private transient volatile Node tail; 
    
    private volatile int state;

	tatic final class Node {
	        /** Marker to indicate a node is waiting in shared mode */
	        static final Node SHARED = new Node();
	        /** Marker to indicate a node is waiting in exclusive mode */
	        static final Node EXCLUSIVE = null;
	
	        /** waitStatus value to indicate thread has cancelled */
	        static final int CANCELLED =  1;
	        /** waitStatus value to indicate successor's thread needs unparking */
	        static final int SIGNAL    = -1;
	        /** waitStatus value to indicate thread is waiting on condition */
	        static final int CONDITION = -2;
	        /**
	         * waitStatus value to indicate the next acquireShared should
	         * unconditionally propagate
	         */
	        static final int PROPAGATE = -3;
	        volatile int waitStatus;
	       volatile Node prev;  
	        volatile Node next;  
	        volatile Thread thread;
	        Node nextWaiter;        
	        final boolean isShared() {
	            return nextWaiter == SHARED;
	        }
	    }

   protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

}

源码解读:

  • 使用了一个int成员变量state来表示同步锁状态,通过内置的FIFO(first-in-first-out)同步队列来控制获取共享资源的线程。请求线程都被封装成Node 节点。

  • 内部state 和Node 内部类的属性都被volatile 关键字修饰,在修改state 和 阻塞队列时 都使用CAS机制循环添加,保证并发安全。

  • 所以可以说AQS就是利用volatile 和CAS的实现

  • 线程的阻塞方法都是使用的unsafe类进行的。

  • 内置的三个修改同步状态的方法

    • int getState() :获取当前同步状态
    • void setState(int newState) :设置当前同步状态
    • boolean compareAndSetState(int expect, int update) 使用CAS设置当前状态。
  • 子类可以重写的方法

    • boolean isHeldExclusively():当前线程是否独占锁
    • boolean tryAcquire(int arg):独占式尝试获取同步状态,通过CAS操作设置同步状态,如果成功返回true,反之返回false,获取同步状态失败,就会通过CAS方式加入队列
    • boolean tryRelease(int arg):独占式释放同步状态。
    • int tryAcquireShared(int arg):共享式的获取同步状态,返回大于等于0的值,表示获取成功,反之失败。
    • boolean tryReleaseShared(int arg):共享式释放同步状态。
  • 进入到队列后,线程的阻塞和唤醒是使用的LockSupportparkunpark 方法来实现的。

  • 比如我们继续深入理解一下AQS的实现类

    • ReentrantLock [riːˈɛntrənt]
      • 上锁的 lock 方法,重写了 tryAcquire,tryAcquire 内部 通过compareAndSetState 方法把 state 设置为1,设置失败,则加入队列,然后调用``LockSupport.park() 阻塞线程
      • unlock 的方法是重写了 tryRelease 方法,使用compareAndSetState 方法修改状态,使用LockSupport.unpark() 来取消阻塞
      • ReentrantLock 内部实现了两种,公平锁和非公平锁的实现
        • 公平锁先判断队列
        • 非公平锁直接先修改状态,失败进入队列
    • CountDownLatch
      • 这个在在新建对象的时候是把state 设置为指定值
      • 调用wait()方法 ,内部实现 tryAcquireShared 获取共享锁,只要 是state 不为0,则获取成功
      • 然后不断调用 countDown() 方法,内部实现 tryReleaseShared,一直怼state 做减操作,直到0
      • state 到0 后 循环队列,调用LockSupport.unpark()
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值