ConcurrentHashMap的实现原理与使用ConcurrentHashMap是线程安全且高效的HashMap。ConcurrentHashMap。
HashMap的Entry链表形成环形数据结构。而jdk1.8引入红黑树的数据结构和扩容的优化。优化内容具体可参照 https://tech.meituan.com/2016/06/24/java-hashmap.html
HashTable效率又非常低下:使用synchronized来保证线程安全,但在线程竞争激烈HashTable的效率非常低下。(jdk1.7,建议弃用)ConcurrentHashMap的锁分段技术可有效提升并发访问率:首先将数据分成一段一段地存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。ConcurrentHashMap的结构
- ConcurrentHashMap的类图
- 结构图
public V get(Object key) {
int hash = hash(key.hashCode());
return segmentFor(hash).get(key, hash);
}
get操作的高效之处在于整个get过程不需要加锁,除非读到的值是空才会加锁重读。
volatile类型,能够在线程之间保持可见性,能够被多线程同时读,并且保证不会读到过期的值,但是只能被单线程写(有一种情况可以被多线程写,就是写入的值不依赖于原值),在get操作里只需要读不需要写共享变量count和value,所以可以不用加锁;volatile字段的写入操作先于读操作,即使两个线程同时修改和获取volatile变量,get操作也能拿到最新的值。由于put方法里需要对共享变量进行写入操作,所以为了线程安全,在操作共享变量时必须加锁。
size操作,先尝试2次通过不锁住Segment的方式来统计各个Segment大小,如果统计的过程中,容器的count发生了变化,则再采用加锁的方式来统计所有Segment的大小。
ConcurrentLinkedQueue基于链接节点的无界线程安全队列。
ConcurrentLinkedQueue类图
阻塞队列使用场景:生产者跟消费者。
ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列,默认不保证线程公平的访问队列,可设置公平性,公平性是使用可重入锁实现。
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。DelayQueue:一个使用优先级队列实现的无界阻塞队列。使用场景:
SynchronousQueue:一个不存储元素的阻塞队列。它支持公平访问队列。默认情况下线程采用非公平性策略访问队列。适合传递性场景。吞吐量高于LinkedBlockingQueue和ArrayBlockingQueue。
public SynchronousQueue(boolean fair) {
transferer = fair new TransferQueue() : new TransferStack();
}
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。原文:https://www.cnblogs.com/lycsmzl/p/13213534.html