Android 价值千万java多线程 AQS CAS 自旋锁 公平锁原理

AbstractQueuedSynchronizer(AQS)队列同步器

手写自旋锁:

 

public class SpinLock {

    private AtomicReference<Thread> cas = new AtomicReference<Thread>();

    public void lock() {

        Thread current = Thread.currentThread();

        // 利用CAS

        while (!cas.compareAndSet(null, current)) {

            // DO nothing

        }

    }

    public void unlock() {

        Thread current = Thread.currentThread();

        cas.compareAndSet(current, null);

    }

}

自旋锁(spinlock):是指尝试去获取锁的线程不会立即阻塞,而是采用循环的方式去获取锁,这样的好处是减少线程上下文切换消耗,缺点是循环会消耗CPU。

 

可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响

synchronized和ReentrantLock都是典型的可重入锁。

 

CAS
:比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令

 

  • 独占锁、共享锁
  • 公平锁、非公平锁、重入锁
  • 条件锁
  • 读写锁 
  • 自旋锁
  • 偏向锁

 

 

  1. node.prev = t;

  2. if (compareAndSetTail(t, node)) {

  3. t.next = node;

  4. return t;

  5.  

该方法就是循环调用CAS,compareAndSetTail  即使有高并发的场景,无限循环将会最终成功把当前线程追加到队尾(或设置队头)。总而言之,addWaiter的目的就是通过CAS把当前线程追加到队尾,并返回包装后的Node实例。

CAS:

 

4. 关于AQS的问题总结

1. 什么是AQS?与锁的区别和联系?

 

AQS:AbstractQueuedSynchronizer,队列同步器。

AQS与锁的区别和联系:

AQS是实现锁和其他同步组件的基础框架

AQS是面向锁的实现者,它简化了锁的实现方式,屏蔽了同步状态管理,线程的排队、等待与唤醒等底层操作。

锁是面向使用者,它定义了使用者与锁交互的接口,隐藏了实现细节。

AQS和锁有效的隔离了实现者和使用者所需关注的领域。

2. AQS中,自定义同步器需要重写哪些方法?

 

基础: AQS中5种指定的可重写方法的名称、作用,tryAcquire()的实现:compareAndSetState()。

进阶: 以实现锁为例,讲解如何使用同步器的实现自定义锁。

3. AQS是什么?底层如何实现?

 

关于如何为实现:

两个核心(同步状态和同步队列)

更改同步状态的三种核心方法

同步队列的结构、如何设置尾节点(需要CAS保证)和头结点(不需要CAS保证)

————————————————

版权声明:本文为CSDN博主「晓之木初」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

 

 

 总结下独占式同步状态的获取和释放:在获取同步状态时,同步器维护一个同步队列,获取状态失败的线程都会被加入到队列中并在队列中进行自旋;移出队列的条件是前驱节点为头节点且成功获取了同步状态。在释放同步状态时,同步器调用tryRelease方法释放同步状态,然后唤醒头节点的后继节点。

 

4、AQS应用

 

    AQS定义两种资源共享方式:Exclusive(独占,只有一个线程能执行,如ReentrantLock)和Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。

 

 

  AQS被大量的应用在了同步工具上。

  ReentrantLock:ReentrantLock类使用AQS同步状态来保存锁重复持有的次数。当锁被一个线程获取时,ReentrantLock也会记录下当前获得锁的线程标识,以便检查是否是重复获取,以及当错误的线程试图进行解锁操作时检测是否存在非法状态异常。ReentrantLock也使用了AQS提供的ConditionObject,还向外暴露了其它监控和监测相关的方法。

  ReentrantReadWriteLock:ReentrantReadWriteLock类使用AQS同步状态中的16位来保存写锁持有的次数,剩下的16位用来保存读锁的持有次数。WriteLock的构建方式同ReentrantLock。ReadLock则通过使用acquireShared方法来支持同时允许多个读线程。

  Semaphore:Semaphore类(信号量)使用AQS同步状态来保存信号量的当前计数。它里面定义的acquireShared方法会减少计数,或当计数为非正值时阻塞线程;tryRelease方法会增加计数,在计数为正值时还要解除线程的阻塞。

  CountDownLatch:CountDownLatch类使用AQS同步状态来表示计数。当该计数为0时,所有的acquire操作(对应到CountDownLatch中就是await方法)才能通过。

  FutureTask:FutureTask类使用AQS同步状态来表示某个异步计算任务的运行状态(初始化、运行中、被取消和完成)。设置(FutureTask的set方法)或取消(FutureTask的cancel方法)一个FutureTask时会调用AQS的release操作,等待计算结果的线程的阻塞解除是通过AQS的acquire操作实现的。

  SynchronousQueues:SynchronousQueues类使用了内部的等待节点,这些节点可以用于协调生产者和消费者。同时,它使用AQS同步状态来控制当某个消费者消费当前一项时,允许一个生产者继续生产,反之亦然。

       除了这些j.u.c提供的工具,还可以基于AQS自定义符合自己需求的同步器。

 

       AQS就学习到这,如果有描述不当的地方,还请留言交流。了解了AQS后下一步准备详细学习基于AQS的工具类。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值