JUC 并发类及并发相干类概览,继续补充 …
- AQS
外部有两个队列,一个期待队列(前后节点),一个条件队列(后继节点),其实是通过链表形式实现;
期待队列是双向链表;条件队列是单向链表;条件队列如果被唤醒,将后接到期待队列上;
通过外部持有的 state,加以模板模式,提供了两种资源争抢模式:排他、共享;而在争抢时,又辅以偏心、非公平竞争的思考;
排他与共享别离通过子类实现的:boolean tryAcquire
和(tryAcquireShared(x) >= 0
来判断获取资源是否胜利,同时排他限度:state 只能被一个线程批改(个别批改为 1,CAS(0,1)
,可重入);而共享则反对多线程同时更改 state 值(被多个线程获取);
获取时要思考是否关注中断唤醒行为,对应办法名后缀:-Interruptible
,关注则抛异样,不关注则革除线程的中断标记位记录,持续挂起直到获取胜利,再中断线程;
总的下来,分支思考就是:资源类型(是否排他)-> 是否偏心 -> 是否关注中断(每一个都是两个方向)
;
开释资源时,排他类型须要判断是否以后线程,而共享类型不须要判断线程,只关注资源池;排他类型会唤醒期待队列的下一个节点,而共享则会通过级联形式传递信号,从 head 开始唤醒,直到资源被新唤醒的线程抢光才进行;
线程的挂起是通过LockSupport.park(thread)
,反对限时挂起;
state 开释导致期待队列判断,进而唤醒。限时挂起必然反对中断响应;
条件队列因为初始时是通过new ConditionObject()
,能够屡次创立,所以反对多个条件队列,应用同一个对象即是同一个条件队列;被唤醒时会执行 state 的资源获取,获取不到则进入期待队列;同样反对是否中断关注;而条件队列的中断有两种状况,一种在条件队列上被中断唤醒,一种是在进入期待队列后被中断唤醒;
AQS 次要是资源 state 的 CAS 并发及线程中断挂起,排队的管制 - AQLS
state 的类型为 long,扩大了并发数(将来扩大)。其余与 AQS 雷同。
long 须要关注缓存行问题。 - ReentrantLock
基于 AQS 实现的锁,设置 state = 1;反对偏心与非偏心(判断队列是否有期待线程);反对重入,state 递增;竞争时只有state = 0
才获取锁胜利,否则进入期待队列;
反对 condition 的 await 和 signal。 - CopyOnWriteArrayList
与 AQS 无关,应用的 synchronized 保障同步平安;当产生增加行为时,会将原数组拷贝一份进行增加,而后更新援用;当产生指定索引增加时,会定位索引,分两步进行拷贝(索引前、索引后);适宜读多写少场景;addIfAbsent 会先判断(无同步锁),而后拷贝(有同步锁),判断时会先拷贝一份快照,在更新索引时判断快照是否最新,是则间接应用,否则从新拷贝; - CopyOnWriteArraySet
底层应用了 CopyOnWriteArrayList。唯一性的增加则是应用了 addIfAbsent。其余大部分办法间接调用了 CopyOnWriteArrayList 的相似办法; - CountDownLatch
应用了 AQS,初始化大小即为 state,每次 countDown 都是对state - 1
,而 await 则是在判断getState() == 0 ? 1 : -1
不通过挂起在队列中,所以有多少 state 则其会被唤醒 state 次,而后从新挂起,直到state = 0
; - ArrayBlockingQueue
未间接应用或继承 AQS,而是通过应用 ReentrantLock 和 Condition 来实现多线程同步与挂起;
外部应用数组存储元素,但不会扩大,实现了环形队列存储,队列元素减少offer
及获取poll
都应用 lock 进行同步;
当增加胜利时,进行notEmpty.signal()
告诉,唤醒获取失败的线程(notEmpty.await()
) 解决;
当获取胜利时,进行notFull.signal()
告诉,唤增加失败的线程(notFulll.await()
) 解决;offer(E)
增加返回true/false
;add(E)
外部调用offer
,返回 false 则抛异样;put
自实现,无奈增加则阻塞;poll()
获取返回E/null
,take
自实现,如果获取不到则阻塞挂起;
任何增加或获取胜利,相应的都会进行notEmpty
与notFull
告诉,而失败则进入相同的队列挂起;
ArrayBlockingQueue 的并发遍历实现是通过队列延展实现的(就是一个队列,一直的翻滚);相似于环形队列