Java多线程 -- JUC包源码分析5 -- Condition/ArrayBlockingQueue/LinkedBlockingQueue/Deque/PriorityBlockingQueu
来源:互联网 发布:sql server 教材 编辑:程序博客网 时间:2024/05/29 10:02
await – signal – signalAll
以下代码,分别展示了wait/notify, 和Condition的await/signal的用法
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
通过以上代码,明确3点:
(1)Condition必须与锁协同使用:对应synchronized来说,wait()的object必须是synchronized对应的同步对象;对应ReentrantLock来说,Condition是通过ReentrantLock.newCondition()得到的。
(2)wait()/await()的时候,会先释放锁,然后进入阻塞,然后被notify/signal唤醒之后,会再去拿锁!也就是其内部有3个环节:
//释放锁
//进入阻塞
//被唤醒,拿锁,执行后续代码
(3)await/signal在使用上,比wait/notify更加灵活:
wait/notify只能附属在一个条件上,所有的阻塞线程都在这1个条件上;
而Lock可以创建多个condition,每个condition都有wait/notify,每个condition都有一个自己的阻塞线程队列。
后面所讲的BlockingQueue,将很好的展示condition的这个优点。
Condition源码分析
从上面的第(2)条可以看出,await()的时候,线程要进入阻塞。所以每个Condition内部,都维护了一个链表,或者说队列,存储所有阻塞在这个条件上的线程。
以下代码,展示了Condition的内部结构:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
下面看一下Condition.await()的源码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
由上述代码可以看出,await()是会响应中断的。下面看一下屏蔽中断的await(),即awaitUninterruptibly()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
下面看一下signal()的源码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
关键点:无论await(), 还是signal(),都是在拿到锁之后执行的,所以其内部的入队/出队,都不需要加锁!
ArrayBlockingQueue
通常的Queue,一边是生产者,一边是消费者。一边进,一边出,有一个判空函数,一个判满函数。
而所谓的BlockingQueue,就是指当为空的时候,阻塞消费者线程;当为满的时候,阻塞生产者线程。
以下是ArrayBlockingQueue的核心结构:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
以下为其主要的构造函数:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
以下为其put()/take()源代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
顺便说一句:上述2个函数,都是响应中断,并且阻塞的。
另外还有不响应中断的,不阻塞的成员函数,在此就不再详述了。
LinkedBlockingQueue
LinkedBlockingQueue是一种基于单向链表的阻塞队列。因为头和尾是2个指针分开操作的,所以用了2把锁 + 2个条件,同时一个AtomicInteger的原子变量记录count数。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
LinkedBlockingDeque
其原理和ArrayBlockingQueue是一样的,也是1把锁 + 2个条件。只是其数据结构不是数组,而是一个双向链表。
有一个小细节:链表不是无限长吗,怎么会满呢?这里是人为设置了一个最大长度:
- 1
- 2
- 3
- 1
- 2
- 3
下面是其主要结构:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
下面是其put/take函数,其原理和ArrayBlockQueue的put/take类似:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
PriorityBlockingQueue
和上面的BlockingQueue有2个区别:
(1)是无界的,所以只有notEmpty一个条件。put不会阻塞,只有take会阻塞
(2)通过2叉堆,实现Priority
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
SynchronousQueue
SynchronousQueue是一种特殊队列,内部不是用Lock + Condition实现的。后续会单独用一篇专门阐述。
- Java多线程 -- JUC包源码分析5 -- Condition/ArrayBlockingQueue/LinkedBlockingQueue/Deque/PriorityBlockingQueu
- Java多线程 -- JUC包源码分析5 -- Condition/ArrayBlockingQueue/LinkedBlockingQueue/Deque/PriorityBlockingQueue
- JUC - Condition 源码分析
- Java多线程 -- JUC包源码分析10 -- ConcurrentLinkedQueue源码分析
- Java多线程 -- JUC包源码分析11 -- CyclicBarrier源码分析
- Java多线程 -- JUC包源码分析12 -- ThreadPoolExecutor源码分析
- Java多线程 -- JUC包源码分析16 -- Exchanger源码分析
- Java LinkedBlockingQueue和ArrayBlockingQueue分析
- Java LinkedBlockingQueue和ArrayBlockingQueue分析 .
- Java LinkedBlockingQueue和ArrayBlockingQueue分析
- Java多线程 -- JUC包源码分析1 -- CAS/乐观锁
- Java多线程 -- JUC包源码分析3-- volatile/final语义
- Java多线程 -- JUC包源码分析6 -- ConcurrentHashMap
- Java多线程 -- JUC包源码分析15 -- SynchronousQueue与CachedThreadPool
- Java多线程 -- JUC包源码分析19 -- ForkJoinPool/ForkJoinTask
- Java多线程 -- JUC包源码分析1 -- CAS/乐观锁
- Java多线程 -- JUC包源码分析3-- volatile/final语义
- [源码]Condition的原理,简单案例(ArrayBlockingQueue),复杂案例(LinkedBlockingQueue).
- 基于Dragonboard 410c的mic和speaker的loopback调试
- [NOIP模拟][分块]subset
- 微信开发第一步(接入配置)
- OneCache-针对redis代理服务
- Linux信号(二)-- signal()函数
- Java多线程 -- JUC包源码分析5 -- Condition/ArrayBlockingQueue/LinkedBlockingQueue/Deque/PriorityBlockingQueu
- RAID详解[RAID0/RAID1/RAID10/RAID5]
- 基于深度学习的人脸识别技术综述
- Kotlin与Java不兼容的情况
- nodejs入门(08)-全局对象
- yum-下载rpm包
- 删除指定目录下指定的文件(非并发)
- Java 下拉框多选 、富文本 【只列出关键部分】
- Struts2的自定义拦截器