阻塞式队列--BlockingQueue
遵循先进先出的原则。阻塞式队列本身使用的时候是需要指定界限。(容量)
1.ArrayBlockingQueue -- 阻塞式顺序队列-->底层基于数组存储。
主要方法:
添加方法:
Add:如果队列已满,则抛出异常--》IllegalStateException
offer:返回元素是否添加到队列中,如果队列已满,则返回false
put:如果队列已满,会产生阻塞--直到这个队列中有元素被取出
相对应的取出方法:
remove:队列为空,抛出异常:NoSuchElementException
poll:队列为空,返回Null
take:队列为空产生阻塞,直到队列中有元素放入
2.LinkedBlockingQueue - 阻塞式链式队列 -底层是基于链表(节点)来进行存储,默认容量为Integer.MAXz_VALUE
3.PriorityBlockingQueue - 具有优先级的阻塞式队列 -- 如果不指定容量是11.如果将元素取出,那么会对元素进行自然排序 -- 要求存储的对象所对应的类必须实现Comparable的compareTo方法。
4.SynchronousQueue -- 同步队列 - 只允许存储一个元素
HashMap:
Jdk1.7
HashMap中核心的成员变量参数详解;
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
初始化桶大小,因为底层是数组,所以这是数组默认的大小。
static final int MAXIMUM_CAPACITY = 1 << 30;
桶最大值
static final float DEFAULT_LOAD_FACTOR = 0.75f;
默认加载因子
4.桶的大小,可在初始化时显式指定。
5.负载因子,可在初始化时显式指定
HashMap(int initialCapacity, float loadFactor) |
负载因子:
给定的默认容量为16,负载因子为0.75.Map在使用过程中不断的向集合中添加数据:
当桶的数量达到16*0.75=12 时就需要将当前16的容量进行扩容,扩容的过程涉及到rehash、复制数据,很耗费性能。
所以加载因子过小,会导致平凡发生rehash操作,减低效率,同时造成空间的浪费。
加载因子过大会导致每个桶的链过长,导致查找效率变慢。
提前预估长度,设置桶的大小和加载因子会降低rehash,提高性能
JDK1.8:
Jdk.7的HashMap在数据量增大时,会将桶中的链表增长,查询效率会变慢;链表的查询效率为O(n)。
基于这一点:
Jdk1.8:在桶中的链表的元素个数超过8个时,会将桶中的链表扭转成一颗红黑树,如果桶中的元素不足8个,会将红黑数在扭转回链表。
ConcurrentHashMap:
HashMap在全程实现时未考虑多线程并发安全问题,在多线程读写时会出现安全问题。
所以有2种并发表解决:
1.HashTable,几乎每个方法都加了Synchronized关键字,用来保证并发安全,但同一时间只允许一个线程进入,及其影响效率。
2.ConcurrentHashMap:
JDK1.7:
和HashMap实现类似,但区别是在其中的核心数据上和链表上都加了volatile修饰的关键字,保证了获取时的可见性。
transient volatile Node<K,V>[] table;
private transient volatile Node<K,V>[] nextTable;
private transient volatile int sizeCtl;
并且采用分段(分桶锁机制),分段锁采用的是读写锁机制(
读锁:允许多个线程读,但是不允许线程写;写锁:允许一个线程写,但是不允许线程读)
JDK1.8:
JDK1.7中的并发映射:缺点是查询遍历链表效率低:
Jdk1.8:在桶中的链表的元素个数超过8个时,会将桶中的链表扭转成一颗红黑树,如果桶中的元素不足8个,会将红黑数在扭转回链表。
且不在采用锁机制来进行并发安全:
而是采用CAS(Compare and Swap)+ synchronized 来保证并发安全性。
基本概念:
--内存值V,旧的预期值A,新的预期值B
过程:先更具内存值V找到变量的实际值,然后将实际值和旧的预期值A进行比较,如果一致,则将新的预期值B赋值给对应变量,并且将A改为B;如果实际值和A不相等将现在的值赋值给A,然后重新比较。