diff --git a/blogs/Java/口水话/集合源码.md b/blogs/Java/口水话/集合源码.md index f327980..f7089ab 100644 --- a/blogs/Java/口水话/集合源码.md +++ b/blogs/Java/口水话/集合源码.md @@ -142,7 +142,7 @@ ConcurrentHashMap 的 get 和 HashMap 基本无差。 #### LinkedBlockingQueue -LinkedBlockingQueue 即链表阻塞队列,它实现了 BlockingQueue 接口,BlockingQueue 在 Queue 的基础上加上了阻塞的概念;链表维护了先入先出的队列,新元素被放在队尾,获取元素从队头拿;当我们调用 put 时,队列满了就一直阻塞,也可以调用 offer 阻塞一段时间返回 false,调用 take 时,如果队列为空也是一直阻塞,也可以调用 poll 阻塞一段时间返回 null。 +LinkedBlockingQueue 即链表阻塞队列,它实现了 BlockingQueue 接口,BlockingQueue 在 Queue 的基础上加上了阻塞的概念;链表维护了先入先出的队列,新元素被放在队尾,获取元素从队头拿;当我们调用 put 时,队列满了就一直阻塞,在阻塞时被其他线程设置了中断标志,则被阻塞的线程会抛出 InterruptedException 异常而返回,也可以调用非阻塞的 offer 方法,如果队列满了就放弃当前元素返回 false;调用 take 时,如果队列为空也是一直阻塞,也可以调用非阻塞的 poll 方法,如果队列为空就直接返回 null。 LinkedBlockingQueue 内部构成简单来说,可以分为三个部分:链表存储 + 锁 + 迭代器。它内部有两把 ReentrantLock 锁,分别是 put 锁和 take 锁,保证了队列操作的线程安全,设计两把锁,是为了 put 和 take 两种操作可以同时进行,互不影响。 @@ -150,6 +150,8 @@ LinkedBlockingQueue 内部构成简单来说,可以分为三个部分:链表 在 take 时,也是先加 take 锁,然后判断队列是否为空,为空就无限等待,否则就删除链表头节点返回,如果这时队列没有满,就唤醒一个 put 的等待线程,最后在解锁。 +在 remove 时会获取双重锁,获取后,其他线程进行入队或出队操作都会被阻塞挂起,然后遍历队列找到要删除的元素删除,找到了就删除并唤醒一个阻塞的 put 线程,否则返回 false。 + LinkedBlockingQueue 主要用在线程池中,当我们使用 Executors 的 newFixedThreadPool 或 newSingleThreadPool 创建线程池时,阻塞队列用的就是 LinkedBlockingQueue,但是通常我们不建议这样直接使用 Executors 创建线程池,因为 LinkedBlockingQueue 的默认队列大小是 Integer.MAX_VALUE,可能会爆内存。 在 Android 中,AsyncTask 在核心线程池不够用的情况下触发任务拒绝策略时,会用到 LinkedBlockingQueue。