容器全家福:
![](https://img-blog.csdnimg.cn/20210206164924646.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM3NDMyMzI=,size_16,color_FFFFFF,t_70)
容器包含:集合、map、数组
物理上存储结构:连续存储的数组Array,非连续存储的链表Linked
Queue是专门为了高并发准备的
早期只有hashtable和vector,而且这两个的所有方法都完全的加了synchronize,二者已淘汰
hashtable hashmap ConcurrentHashmap synchronizeMap对比:
hashmap有两个版本:一个是普通的hashmap,另一个是加锁版本的Collections.synchronizeMap
hashmap完全没有加锁,所以效率高,但是线程不安全
Collections.synchronizeMap,效率也不高,跟hashtable差不多
ConcurrentHashmap的插入效率没有synchronizeMap和hashtable高,原因在于中间检查的东西比较多,还有大于8个转成红黑树的机制,导致了插入效率比较慢.但是读的效率比较高
hashtable和synchronizeMap的读效率很低,ConcurrentHashmap读的效率比前两者高得多
下面是四种map的对比图
![](https://img-blog.csdnimg.cn/20210206164924717.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM3NDMyMzI=,size_16,color_FFFFFF,t_70)
各版本没有相互替代关系,按照具体情况来分析使用.最好使用面向接口编程,业务和实现分开.这样方便与做压力测试对比效率
ConcurrentHashmap通过加入了链表实现,所以迭代的效率高
Treemap的实现是红黑树树中排好顺序了
ConcurrentSkipmap是跳表结构
跳表结构如下图:
![](https://img-blog.csdnimg.cn/20210206164924714.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM3NDMyMzI=,size_16,color_FFFFFF,t_70)
链表查询必须要从头查到尾,为了改善查询效率,出现了跳表.跳表底层是链表,然后会提取链表中的关键元素向上提取,并不断向上提取,分成多层链表.查询的时候从顶层开始查询,到最后一层.
CopyOnWrite(写时复制):写入的时候复制一份.用于读特别多,写特别少的情况
读的时候不加锁
![](https://img-blog.csdnimg.cn/20210206164924610.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM3NDMyMzI=,size_16,color_FFFFFF,t_70)
写的时候将array复制,并追加元素到新的array中,然后将指向转向新的array,如下图
![](https://img-blog.csdnimg.cn/20210206164924657.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM3NDMyMzI=,size_16,color_FFFFFF,t_70)
Queue:
Queue内置方法:offer add peak poll
BlockingQueue:阻塞原理是ReentrainLock和Condition,用await方法实现的.而await的底层是LockSupport.park实现的
BlockingQueue内置方法:offer add peak poll put take
put是一定要将元素装入,装不进去就阻塞
take是一定要将元素取出,取不到就阻塞
LinkedBlockingQueue: 如果不指定容量,默认为Integer.MAX_VALUE,也就是无界队列, 所以为了避免队列过大造成机器负载或者内存爆满的情况出现,我们在使用的时候建议手动传一个队列的大小,
ArrayBlockingQueue:对象时在其构造方法附上一个capacity(
new LinkedBlockingQueue(4) ).数据可以一直添加入链表直到内存占满
ConcurrentLinkedQueue
ConcurrentLinkedQueue添加数据用offer,如果添加进去了返回true,还可以设置时间,添加不进去返回false.peek是取的方法,只取不删.poll是取的方法,取完不删.
Queue和List的区别在哪里?
添加了一系列对线程友好的api,如offer peek poll.BlockingQueue在Queue的基础上又添加了put和take进行阻塞
DelayQueue:是BlockingQueue的一种,取的时候是按照等待时间/紧迫程度进行排序取出来的
![](https://img-blog.csdnimg.cn/20210206164924700.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM3NDMyMzI=,size_16,color_FFFFFF,t_70)
PriorityQueue优先级排序:按照优先级排序,越小的越放在前面
![](https://img-blog.csdnimg.cn/20210206164924651.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM3NDMyMzI=,size_16,color_FFFFFF,t_70)
SynchronusQueue(同步Queue,线程同步,数据传递):容量为0,用来让一个线程给另一个线程下达任务.使用put来等待消费者消费,消费者take出现的时候put中的值传递给了take.用作线程间交换数据
![](https://img-blog.csdnimg.cn/20210206164924664.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM3NDMyMzI=,size_16,color_FFFFFF,t_70)
TransferQueue(传递Queue,线程同步,数据传递):
![](https://img-blog.csdnimg.cn/20210206164924701.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM3NDMyMzI=,size_16,color_FFFFFF,t_70)
transfer和put的区别:put只负责装填且在容器满了之后进入阻塞等待消费,transfer直接等待消费者消费完并且给出结果后才会结束并且执行下一步
参考:
Java 集合系列之四:Queue基本操作