资源是可以被同时访问还是在同一时间只能被一个线程访问(共享/独占)
访问资源的线程如何进行并发管理(等待队列)
如果线程等不及资源了,如何从等待队列退出(超时/中断)
常见同步器对资源以及对资源访问这个问题的定义
ReentrantLock
资源表示独占锁,state为0表示锁可用,为1表示被占用,为n表示可重入以及次数
CountDownLatch
资源表示倒数计数器,state为0表示所有的线程都可以访问资源,为n表示所有线程都需要阻塞
Semaphore
资源表示信号量或令牌,state<=0表示所有线程都需要阻塞,>0表示有令牌可用,线程每获取一个令牌state减1,线程每释放一个令牌state加1
ReentrantReadWriteLock
资源表示共享的读锁和独占的写锁,state逻辑上被分为两个16位的unsigned short,分别记录读锁被多少线程使用和写锁被重入的次数
AQS通过暴露以下API来解决如何定义资源是否可以被访问的问题
一、同步状态的管理
AQS使用单个int来保存同步状态,并通过getState、setState、compareAndSetState来读取和更新这个状态。
二、数据结构
AQS内部维护着一个FIFO的队列,该队列用来实现线程的并发访问控制。队列中的元素是一个Node类型的节点。
1、waitStatus:表示节点的状态
CANCELLED:值为1,表示当前节点被取消
SIGNAL:值为-1,表示当前节点的后继节点将要或已经被阻塞
CONDITION:值为-2,表示当前节点在等待condition,在condition队列中
PROPAGATE:值为-3,表示releaseShared需要被传播给后续节点
INITAL:值为0,默认状态,新节点处于该状态
2、prev:前置节点
3、next:后置节点
4、nextWaiter:存储condition队列中的后置节点
5、thread:当前线程
当线程请求资源时,如果请求不到,会将线程包装成节点,将其插入队列的尾部
1、初始状态,队列head、tail都指向空
2、首个线程入队,先创建一个空的头节点,然后以自旋的方式不断尝试插入一个包含当前线程的新节点
欢迎关注我的微信公众号,分享leetcode解题心得和Java后端的相关知识