Android-AQS
Posted 天津 唐秙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android-AQS相关的知识,希望对你有一定的参考价值。
AQS
什么是AQS?
AQS,全程AbstractQueuedSynchronizer,位于java.util.concurrent.locks包下,是JDK1.5提供的一套用于实现阻塞锁和一系列依赖FIFO等待队列的同步机器(First Input First Output先进先出)的框架实现,是除了java自带的synchronized关键字之外的锁机制,可以将AQS作为一个队列来理解。
我们常用的ReentrantLock,Semaphore,CountDownLatch,CyclicBarrier等并发类均是基于AQS来实现的,具体用法是通过继承AQS,并实现其模板方法,来达到同步状态的管理。
AQS的功能在使用中可以分为两种:独占锁和共享锁
独占锁:每次只能有一个线程持有锁,ReentrantLock就是独占锁
共享锁:允许多个线程同时获得锁,并发访问共享资源,ReentrantReadWriteLock中的读。
核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态,如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
doglee帮我们搭出了一个基础的锁实现的架子,ReentrantLock是doglee帮我们实现的锁。
重点
本质:是提供自己去写锁的一个规范,从使用的角度就是自己去继承和实现AbstractQueuedSynchronizer,但是具体已经有人帮我们写了ReentrantLock,ReentrantLockReadWriteLock读写锁,AQS体系实现了不同的对于锁的应用,AQS是依托业务来开发并发工具,底层原理应用的是CAS原子变量+队列+Park+unpark的支撑来添加业务去具体实现锁的定义。
synchronize是底层对于基础锁的支持。
AQS使用方法
AQS设计是基于模板方法模式的,一般的使用方式是:
1.使用者继承AbstractQueuedSynchronizer并重写指定的方法,这些重写方法很简单,无非是对共享资源state的获取和释放。
2.将AQS组合在自定义同步组件的实现中,并调用其模板方法,而这些模板方法会调用使用者重写的方法
AQS定义的这些可重写的方法:
protected boolean tryAcquire(int arg):独占式获取同步状态,试着获取,成功返回true,反之为false
protected boolean tryRelease(int arg):独占式释放同步状态,等待中的其他线程此时将会有机会获取到同步状态。
protected int tryAcquireShared(int arg):共享式获取同步状态,返回值大于等于0,代表获取成功,反之失败
protected boolean tryReleaseShared(int arg):共享式释放同步状态,成功为true,失败为false
protected boolean isHeldExclusively():是否在独享模式下被线程占用
AQS的模板方法
独占锁可以理解为synchronize
ReentrantLock分析
1.怎么加锁?
1.1 竞争成功
if(compareAndSetState(0,1))//原子的函数,true
setExclusiveOwnerThread(Thread.currentThread());
1.2 竞争不成功
获取当前线程
获取状态
重试 成功就竞争成功
不成功锁重入(锁重入,规避死锁,默认状态值往上递增,其实就是做了一次计数)
!tryAcquire(arg)进行尝试与重入处理,如果还不行 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
主要功能:
addWaiter进行入队的
acquireQueued进行park等待唤醒的=wait
!tryAcquire(arg)进行尝试与重入处理
2.怎么解锁?
3.内部的阻塞队列是啥?
4.ReentrantLock原理
默认是非公平锁
同步方案对比
wait/notify:依托于synchronized,基于VM底层对于阻塞的实现,使用waitSet作为等待机制
await/signal:依托于ReentrantLock条件变量,已经用条件变量与AQS体系作为唤醒机制,本质上层次是partk/unpark实现阻塞
park/unpark:以thread为操作对象,操作更精准,可以准确的唤醒某一个线程(notify随机唤醒一个线程,notifyAll唤醒所有等待的线程),增加了灵活性。
Object obj = new Object();
synchronized(obj)
try
obj.wait();
catch(InterruptedException e)
e.printStackTrace();
wait/notify本身依托于Monitor对象,因此,必须放到synchronized中去,这样才能找到waitset
并发编程的总结:
1.内存模型(最根本的是吸收JAVA对于线程处理在内存数据角度的本质是什么)
2.JVM锁机制(Java常规情况下对于同步处理的手段是怎么做的)
3.原子变量-CAS无锁并发(常规手段的优化–>CAS理论来支撑对于无锁并发的处理)
4.线程池(对于线程的优化在于如何合理的利用CPU的核数的优势)
5.AQS(如何针对专门的业务,利用CAS与PARK机制,完成对于特殊业务定制化同步诉求)
6.三高的处理(涉及到服务端)
以上是关于Android-AQS的主要内容,如果未能解决你的问题,请参考以下文章
什么是最好的灵活性,为什么?使用数据库视图、数据库表、存储过程。和表中的对象
Effective Java 第三版——31.使用限定通配符来增加API的灵活性