ConcurrentReferenceHashMap
ConcurrentReferenceHashMap
官方描述:一个Concurrent的HashMap,对键和值使用软引用或弱引用。在并发访问时支持更好的性能,可用作Collections.synchronizedMap(new WeakHashMap<K,Reference<V>>())的替代品。此实现遵循与ConcurrentHashMap相同的设计约束,支持null的key或value。
从以上描述可以看出,这个类是WeakHashMap的Concurrent版,并且支持SoftReference和WeakReference(默认是SoftReference,可以通过构造方法指定)
既然可用作Collections.synchronizedMap(new WeakHashMap<K,Reference<V>>())的替代品,就要先介绍一下WeakHashMap。
WeakHashMap
Entry<K,V>[] table; 其Entry继承了WeakReference
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
在使用put(K,V)时,就会使用K,V,ReferenceQueue等参数构造Entry,因此GC时Entry就会进入queue
在使用get(K)、size() 等方法时,就会触发private void expungeStaleEntries() 使用queue.poll()识别哪些Entry已经被回收,重新整理table达到数据是实时的效果
private static final int DEFAULT_INITIAL_CAPACITY = 16;
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
private static final ReferenceType DEFAULT_REFERENCE_TYPE = ReferenceType.SOFT;
private static final int MAXIMUM_CONCURRENCY_LEVEL = 1 << 16;
private static final int MAXIMUM_SEGMENT_SIZE = 1 << 30;
private final Segment[] segments; 使用Segment作为hash分段桶,桶内的 写操作 使用lock
构造参数有4个,int initialCapacity, float loadFactor, int concurrencyLevel, ReferenceType referenceType 默认值分别对应以上常量
#protected final float getLoadFactor() return this.loadFactor;
#protected final int getSegmentsSize() return this.segments.length;
#protected final Segment getSegment(int index) return this.segments[index];
#protected ReferenceManager createReferenceManager() return new ReferenceManager();
#protected int getHash(@Nullable Object o) 计算key的hash
@Nullable
#public V get(@Nullable Object key) 委托getReference(@Nullable Object key, Restructure. Restructure restructure) Restructure.WHEN_NECESSARY
@Nullable
#public V getOrDefault(@Nullable Object key, @Nullable V defaultValue) 若不存在则返回defaultValue,Restructure.WHEN_NECESSARY
#public boolean containsKey(@Nullable Object key) 跟get(@Nullable Object key) 一样先找,找到后再用key的eq,Restructure.WHEN_NECESSARY
@Nullable
#protected final Reference<K, V> getReference(@Nullable Object key, Restructure restructure) 使用key的hash找到Segment,在Segment中找到Reference(Restructure.WHEN_NECESSARY在找之前会先检查ReferenceQueue中是否可以poll到,若有则restructure这个Segment,restructure是使用lock的)
@Nullable
#public V put(@Nullable K key, @Nullable V value) return put(key, value, true);
@Nullable
#public V putIfAbsent(@Nullable K key, @Nullable V value) return put(key, value, false);
@Nullable
#private V put(@Nullable final K key, @Nullable final V value, final boolean overwriteExisting) 使用key的hash找到Segment,执行Segment.doTask(final int hash, @Nullable final Object key, final Task<T> task) ,task参数是个回调(这里的回调逻辑是,若key对应的value已存在,则根据overwriteExisting去覆盖;若不存在则新增)
@Nullable
#public V remove(@Nullable Object key) task回调逻辑是,若找到可移除的Reference,则执行Reference的release,触发java.lang.ref.Reference的enqueue和clear,让它进ReferenceQueue
#public boolean remove(@Nullable Object key, final @Nullable Object value) task回调逻辑比remove(@Nullable Object key) 多value的eq判断
#public boolean replace(@Nullable K key, final @Nullable V oldValue, final @Nullable V newValue) task回调逻辑是,若找到可移除的Reference,若oldValue是eq的,则使用newValue进行覆盖
@Nullable
#public V replace(@Nullable K key, final @Nullable V value) task回调逻辑是,若找到可移除的Reference,则进行覆盖
#public void clear() 执行所有segment的segment.clear();
#public void purgeUnreferencedEntries() 执行所有segment的segment.restructureIfNecessary(false); 重新整理
#public int size() 所有segment的数量累加
#public boolean isEmpty() 是否所有segment都是空的
#public Set<Map.Entry<K, V>> entrySet() 产生一个内部类EntrySet的映射,数据引用ConcurrentReferenceHashMap,不会copy一份新的
@Nullable
#private <T> T doTask(@Nullable Object key, Task<T> task) 使用key的hash找到Segment,执行Segment.doTask(final int hash, @Nullable final Object key, final Task<T> task)
#private Segment getSegmentForHash(int hash) 找Segment的hash算法
以下是内部类
Segment
@Nullable
#public Reference<K, V> getReference(@Nullable Object key, int hash, Restructure restructure) Segment用于找Reference的逻辑封装在这里
@Nullable
#public <T> T doTask(final int hash, @Nullable final Object key, final Task<T> task) Segment.doTask会先检查是否需要restructure,然后根据hash、key找到Reference,无论Reference是否找到,都执行task.execute(ref, entry, entries); 这里的entries参数是个匿名内部类,实现Entries.add,这里实现的逻辑是使用key、value创建Entry,创建Reference并加入到Segment
#public void clear() 重新创建一份private volatile Reference<K, V>[] references;
Reference
接口,定义了新方法
@Nullable
Entry<K, V> get();
int getHash();
@Nullable
Reference<K, V> getNext();
void release();
有2个实现类除了分别继承SoftReference、WeakReference,其他一样
SoftEntryReference<K, V> extends SoftReference<Entry<K, V>> implements Reference<K, V>
WeakEntryReference<K, V> extends WeakReference<Entry<K, V>> implements Reference<K, V>
Entry
封装了K,V
Task
抽象类,2个execute方法
EntrySet
数据映射,数据不独立
EntryIterator
迭代器,数据独立
ReferenceManager
private final ReferenceQueue<Entry<K, V>> queue = new ReferenceQueue<>();
创建Reference,内部管理着ReferenceQueue