Update 集合源码.md

master
Omooo 4 years ago
parent cd749247de
commit 5ccb0f300d
  1. 24
      blogs/Java/口水话/集合源码.md

@ -16,8 +16,10 @@
10. TreeSet 10. TreeSet
11. CopyOnWriteArrayList 11. CopyOnWriteArrayList
12. ConcurrentHashMap 12. ConcurrentHashMap
13. SparseArray 13. LinkedBlockingQueue
14. ArrayMap 14. SynchronousQueue
15. SparseArray
16. ArrayMap
#### ArrayList #### ArrayList
@ -128,6 +130,24 @@ ConcurrentHashMap 在 put 时,在一个 for 死循环里面,也就是一定
ConcurrentHashMap 的 get 和 HashMap 基本无差。 ConcurrentHashMap 的 get 和 HashMap 基本无差。
#### LinkedBlockingQueue
LinkedBlockingQueue 即链表阻塞队列,它实现了 BlockingQueue 接口,BlockingQueue 在 Queue 的基础上加上了阻塞的概念;链表维护了先入先出的队列,新元素被放在队尾,获取元素从队头拿;当我们调用 put 时,队列满了就一直阻塞,也可以调用 offer 阻塞一段时间返回 false,调用 take 时,如果队列为空也是一直阻塞,也可以调用 poll 阻塞一段时间返回 null。
LinkedBlockingQueue 内部构成简单来说,可以分为三个部分:链表存储 + 锁 + 迭代器。它内部有两把 ReentrantLock 锁,分别是 put 锁和 take 锁,保证了队列操作的线程安全,设计两把锁,是为了 put 和 take 两种操作可以同时进行,互不影响。
在 put 时,先调用 ReentrantLock 的 lockInterruptibly 设置可中断锁,然后判断队列是否满了,如果满了就调用 Condition 的 await 函数无限等待,否则就添加到队列尾部;如果这时队列不为空,就唤醒一个 take 的等待线程,最后在解锁。
在 take 时,也是先加 take 锁,然后判断队列是否为空,为空就无限等待,否则就删除链表头节点返回,如果这时队列没有满,就唤醒一个 put 的等待线程,最后在解锁。
LinkedBlockingQueue 主要用在线程池中,当我们使用 Executors 的 newFixedThreadPool 或 newSingleThreadPool 创建线程池时,阻塞队列用的就是 LinkedBlockingQueue,但是通常我们不建议这样直接使用 Executors 创建线程池,因为 LinkedBlockingQueue 的默认队列大小是 Integer.MAX_VALUE,可能会爆内存。
在 Android 中,AsyncTask 在核心线程池不够用的情况下触发任务拒绝策略时,会用到 LinkedBlockingQueue。AsyncTask 它使用是一个单线程池,
#### SynchronousQueue
#### SparseArray #### SparseArray
SparseArray 是 Android 中一种特有的数据结构,用来替代 HashMap 的。初始化时容量为 10,它里面有两个数组,一个是 int[] 数组存放 key,一个是 Object[] value 数组。也就是它的 key 只能为 int;在 put 时,会根据传入的 key 进行二分查找找到合适的插入位置,如果当前位置有值或者是 DELETED 节点,就直接覆盖,否则就需要拷贝数组后移一位,空出一个位置让其插入。如果数组满了但是还有 DELETED 节点,就需要调用 gc 方法,gc 方法所做的就是把 DELETED 节点后面的数前移,也就是真正的把 DELETED 节点删掉然后在插入,否则就只能扩容了。 SparseArray 是 Android 中一种特有的数据结构,用来替代 HashMap 的。初始化时容量为 10,它里面有两个数组,一个是 int[] 数组存放 key,一个是 Object[] value 数组。也就是它的 key 只能为 int;在 put 时,会根据传入的 key 进行二分查找找到合适的插入位置,如果当前位置有值或者是 DELETED 节点,就直接覆盖,否则就需要拷贝数组后移一位,空出一个位置让其插入。如果数组满了但是还有 DELETED 节点,就需要调用 gc 方法,gc 方法所做的就是把 DELETED 节点后面的数前移,也就是真正的把 DELETED 节点删掉然后在插入,否则就只能扩容了。

Loading…
Cancel
Save