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

 

posted on 2021-10-15 11:26  icodegarden  阅读(588)  评论(0编辑  收藏  举报