- 浏览: 14992 次
- 性别:
- 来自: 重庆
最新评论
-
弃天笑:
Agrael 写道dwbin 写道其实就是锁的问题吧?lock ...
不要同时使用ReentrantLock类与synchronized关键字锁定会修改同一个资源的不同方法 -
弃天笑:
刚看了一下,虽然结果是标题说的但是实际上,两种不同的实现机制, ...
不要同时使用ReentrantLock类与synchronized关键字锁定会修改同一个资源的不同方法 -
zhmore:
环境:jboss5.1 struts2.2.1
在EAR内i ...
通过struts2-ejb3-plugin把Struts2与EJB3.0无缝整合起来 -
dennis_zane:
转贴怎么不在开头注明出处?
非阻塞算法-ReentrantLock代码剖析之ReentrantLock.lock -
only_xxp:
学习!!!
非阻塞算法-ReentrantLock代码剖析之ReentrantLock.lock
封装ConcurrentHashMap成为具有各种引用类型key与value的ConcurrentReferenceMap,完美取代WeakHashMap
- 博客分类:
- JAVA EE
在非并发访问时,常用的为HashMap,在并发访问时,常用的是ConcurrentHashMap。但是如果我的键是在不没有强的引用时需要清理呢?那么可以使用WeakHashMap。如果键与值都要有引用效果呢?我推荐ConcurrentReferenceMap。什么?JDK没有这个类?好吧,确实没有,因为这个是我们自己写的。
WeakHashMap有个缺点,它的key在被回收后,不会从WeakHashMap中清除,而是要等下次调用 WeakHashMap的方法时才清除,这样就造成了不及时,所以也不是一个健康的机制。我们在写ConcurrentReferenceMap时,会用到的是 java.lang.ref包下的各个类来帮助我们做好清理工作。其中比较关键的为ReferenceQueue,要及时的清理,也就得依赖它了。
ReferenceQueue的remove方法会一直阻塞到有一个Reference被的对象被回收,然后返回这个对象。我们可以通过该机制来在资源被回收的时候就从Map中清除该Reference中对象的关联。那么首先,我们可以创建一个回调,在Reference中的对象被清理时执行该回调,并继承ReferenceQueue,实现我们需要调用回调的方法。
package cn.agrael.ref; /** * 带有回调清除功能的引用类型。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用对象的类型 */ public interface FinalizableReference<T> { /** * 清除动作的回调方法。在该实现类包装的引用对象被垃圾回收器回收时调用该方法。 */ void finalizeReferent(); }
/** * 执行引用的清除工作。 * @param reference 要执行清除工作的引用。 */ void cleanUp(Reference<?> reference) { try { ((FinalizableReference<?>) reference).finalizeReferent(); } catch (Throwable t) { LOG.error("清除引用时发生错误",t); } }
在有了这些后还不够,我们需要一个守护线程来调用ReferenceQueue的remove方法。
/** * 开始垃圾回收引用监视。 */ void start() { Thread thread = new Thread("清除垃圾回收引用队列") { @Override public void run() { while (true) { try { cleanUp(remove()); } catch (InterruptedException e) { } } } }; thread.setDaemon(true); thread.start(); LOG.info("垃圾回收引用监视器开始工作。"); }
在准备好清理的机制以后,我们需要做的就是key与value各种引用的实现类,同时这些实现类要实现FinalizableReference接口,然后在实现的finalizeReferent方法中,清理自己的印射关系。
/** * 弱引用对象的键类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableKeyWeakReference<T> extends FinalizableWeakReference<T> implements FinalizableReference<T>{ private final int hashCode; /** * 构造一个新的 弱引用对象的键类 实例。 * @param referent 键。 */ protected FinalizableKeyWeakReference(T referent) { super(referent); this.hashCode = keyHashCode(referent); } public void finalizeReferent() { map.remove(this); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object object) { return referenceEquals(this, object); } } /** * 弱引用对象的值类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableValueWeakReference<T> extends FinalizableWeakReference<T> implements FinalizableReference<T>{ private Object keyReference; /** * 构造一个新的 弱引用对象的值类 实例。 * @param keyReference 与此值关联的 键 。 * @param referent 值。 */ protected FinalizableValueWeakReference(Object keyReference ,T referent) { super(referent); this.keyReference = keyReference; } public void finalizeReferent() { map.remove(keyReference,this); } } /** * 软引用对象的键类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableKeySoftReference<T> extends FinalizableSoftReference<T> implements FinalizableReference<T>{ private final int hashCode; /** * 构造一个新的 软引用对象的键类 实例。 * @param referent 键。 */ protected FinalizableKeySoftReference(T referent) { super(referent); this.hashCode = keyHashCode(referent); } public void finalizeReferent() { map.remove(this); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object object) { return referenceEquals(this, object); } } /** * 软引用对象的值类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableValueSoftReference<T> extends FinalizableSoftReference<T> implements FinalizableReference<T>{ private Object keyReference; /** * 构造一个新的 软引用对象的值类 实例。 * @param keyReference 与此值关联的 键 。 * @param referent 值。 */ protected FinalizableValueSoftReference(Object keyReference ,T referent) { super(referent); this.keyReference = keyReference; } public void finalizeReferent() { map.remove(keyReference,this); } } /** * 虚引用对象的键类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableKeyPhantomReference<T> extends FinalizablePhantomReference<T> implements FinalizableReference<T>{ private final int hashCode; /** * 构造一个新的 虚引用对象的键类 实例。 * @param referent 键。 */ protected FinalizableKeyPhantomReference(T referent) { super(referent); this.hashCode = keyHashCode(referent); } public void finalizeReferent() { map.remove(this); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object object) { return referenceEquals(this, object); } } /** * 虚引用对象的值类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableValuePhantomReference<T> extends FinalizablePhantomReference<T> implements FinalizableReference<T>{ private Object keyReference; /** * 构造一个新的 虚引用对象的值类 实例。 * @param keyReference 与此值关联的 键 。 * @param referent 值。 */ protected FinalizableValuePhantomReference(Object keyReference ,T referent) { super(referent); this.keyReference = keyReference; } public void finalizeReferent() { map.remove(keyReference,this); } }
这些类实际被实现为ReferenceMap的内部类,以便获得ReferenceMap中的实例变量的引用。它们的回调方法中都为清除自身到Map的印射关联。
这个时候我们可以想象下,如果我们不是使用的强引用,而是使用弱引用、虚引用或者软引用其中之一,那么我们放入包装的Map中的不就是引用类型吗?这个时候如果我们使用key来查询的话,那我怎么知道是哪个呢?对于这个问题,我们可以提供2个包装器,在引用非强引用类型时,我们使用包装器试得它能与引用类型保持一样的行为,这样我们就能正确的找出 key 了。
/** * 引用类型中的对象的另一个包装器,该包装器实现为引用类型中的对象保持 put 与 get 时用到的 hashCode 和 equals 方法的一致性。 * @author <a href="http://www.agrael.cn">李翔</a> * */ protected static class ReferenceWrapper{ protected final Object reference; /** * 使用一个引用类型中的对象实例构造一个新的包装器。 * @param reference 要包装的引用类型中的对象实例。 */ protected ReferenceWrapper(Object reference) { this.reference = reference; } /** * 得到被包装的对象。 * @return 被包装的对象。 */ protected Object getReference() { return reference; } /** * 调用包装对象的 hashCode 方法。 * @return 包装对象的 hashCode。 */ @Override public int hashCode() { return reference.hashCode(); } /** * 调用包装对象的 equals 方法比较。 * @param obj 要与之比较的对象。 * @return 如果传入的对象和包装对象“相等”则返回 true,否则返回 false。 */ @Override public boolean equals(Object obj) { // 使用包装对象的 equals return reference.equals(obj); } } /** * 专用于 key 的引用类型中的对象的另一个包装器。该包装器重写了 hashCode 方法,使用 {@link System#identityHashCode(Object)} 取得 hash值 。 * @author <a href="http://www.agrael.cn">李翔</a> * */ protected static class KeyReferenceWrapper extends ReferenceWrapper { /** * 使用一个引用类型中的 key对象实例 构造一个新的包装器。 * @param reference 要包装的引用类型中的key对象实例。 */ protected KeyReferenceWrapper(Object reference) { super(reference); } /** * 返回包装的 Key 的内存里的 hashCode。 * @return 包装的 Key 的内存里的 hashCode。 * @see System#identityHashCode(Object) */ @Override public int hashCode() { // 这里要认为同一内存地址的才是相同对象,所以取得内存地址中的 HASH码 return System.identityHashCode(reference); } }
同样,这2个类也为内部类,因为要得到ConcurrentReferenceMap实例变量的引用。
到了这里,我们的清理与包装都成型了,最后就差完成ConcurrentReferenceMap了。
最后上ConcurrentReferenceMap的代码:
package cn.agrael.collection; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.ref.Reference; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import cn.agrael.ref.FinalizablePhantomReference; import cn.agrael.ref.FinalizableReference; import cn.agrael.ref.FinalizableReferenceQueue; import cn.agrael.ref.FinalizableSoftReference; import cn.agrael.ref.FinalizableWeakReference; /** * 支持检索的完全并发和更新的所期望可调整并发并且键值对支持引用类型的哈希表。尽管所有操作都是线程安全的,但检索操作不 必锁定,并且不 * 支持以某种防止所有访问的方式锁定整个表。 * <p> * 检索操作(包括 get)通常不会受阻塞,因此,可能与更新操作交迭(包括 put 和 remove)。检索会影响最近完成的 * 更新操作的结果。对于一些聚合操作,比如 putAll 和 * clear,并发检索可能只影响某些条目的插入和移除。类似地,在创建迭代器/枚举时或自此之后,Iterators 和 Enumerations * 返回在某一时间点上影响哈希表状态的元素。它们不会 抛出 * ConcurrentModificationException。不过,迭代器被设计成每次仅由一个线程使用。 * </p> * <p> * 这允许通过可选的 concurrencyLevel 构造方法参数(默认值为 * 16)来引导更新操作之间的并发,该参数用作内部调整大小的一个提示。表是在内部进行分区的 * ,试图允许指示无争用并发更新的数量。因为哈希表中的位置基本上是随意的, * 所以实际的并发将各不相同。理想情况下,应该选择一个尽可能多地容纳并发修改该表的线程的值 * 。使用一个比所需要的值高很多的值可能会浪费空间和时间,而使用一个显然低很多的值可能导致线程争用 * 。对数量级估计过高或估计过低通常都会带来非常显著的影响。当仅有一个线程将执行修改操作 * ,而其他所有线程都只是执行读取操作时,才认为某个值是合适的。此外,重新调整此类或其他任何种类哈希表的大小都是一个相对较慢的操作 * ,因此,在可能的时候,提供构造方法中期望表大小的估计值是一个好主意。 * </p> * <p> * 引用类型请参考 {@link java.lang.ref}与 {@link cn.agrael.ref} 的描述。 * </p> * <p> * 在第一次调用 put/putAll 方法时(仅仅是在同一个类加载器中的第一次 * ,如果为同一类加载器,那么在put/putAll后,新创建的实例的put/putAll也不算做第一次),会有一个后台线程随之创建并启动 * ,该后台线程主要作用和垃圾回收交互,进行回收对象的清理。在清理 键 的同时,会一同清理掉 键的引用包装器 以及 值 和 值的引用包装器 以及 印射 * ,在清理 值 时 ,会一同清理掉 值的引用包装器,然后从 Map 中移除印射到自身的 键 以及 印射 。 * </p> * <p> * <strong>该清理是 异步 且 “即时” 的,会在垃圾回收的同时清理,不需要在下次对该 Map 操作时才清理包装引用的实例。</strong> * </p> * <p> * 此类及其视图和迭代器实现了 {@link ConcurrentMap} 和 {@link Iterator} 接口的所有可选 方法。 * </p> * <p> * 该实现不支持参数为 null。如果传入 null 则会抛出 {@link NullPointerException}。 * </p> * * @author <a href="http://www.agrael.cn">李翔</a> * * @param <K> * 此映射维护的键类型 * @param <V> * 映射值的类型 */ public class ConcurrentReferenceMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>, Serializable { /** 版本号 */ private static final long serialVersionUID = -6254917146703229097L; private static final FinalizableReferenceQueue FINALIZABLE_REFERENCE_QUEUE = new FinalizableReferenceQueue( "ConcurrentReferenceMapReferenceQueue"); private final ReferenceKeyType keyReferenceType; private final ReferenceValueType valueReferenceType; private transient int initialCapacity = 16; private transient float loadFactor = 0.75f; private transient int concurrencyLevel = 16; private transient ConcurrentMap<Object, Object> map; /** * 通过指定的 key引用类型 和 value引用类型 创建一个带有默认初始容量、加载因子和 concurrencyLevel 的新的空映射。 * @param keyReferenceType key引用类型 。 * @param valueReferenceType value引用类型。 */ public ConcurrentReferenceMap(ReferenceKeyType keyReferenceType, ReferenceValueType valueReferenceType) { this.keyReferenceType = keyReferenceType; this.valueReferenceType = valueReferenceType; this.map = new ConcurrentHashMap<Object, Object>(this.initialCapacity, this.loadFactor, this.concurrencyLevel); } /** * 通过指定的 key引用类型 和 value引用类型 创建一个带有指定初始容量、默认加载因子和 concurrencyLevel 的新的空映射。 * @param keyReferenceType key引用类型。 * @param valueReferenceType value引用类型。 * @param initialCapacity 初始容量。该实现执行内部大小调整,以容纳这些元素。 */ public ConcurrentReferenceMap(ReferenceKeyType keyReferenceType, ReferenceValueType valueReferenceType, int initialCapacity) { this.keyReferenceType = keyReferenceType; this.valueReferenceType = valueReferenceType; this.initialCapacity = initialCapacity; this.map = new ConcurrentHashMap<Object, Object>(initialCapacity, this.loadFactor, this.concurrencyLevel); } /** * 通过指定的 key引用类型 和 value引用类型 创建一个带有指定初始容量、加载因子和并发级别的新的空映射。 * @param keyReferenceType key引用类型。 * @param valueReferenceType value引用类型。 * @param initialCapacity 初始容量。该实现执行内部大小调整,以容纳这些元素。 * @param loadFactor 加载因子阈值,用来控制重新调整大小。在每 bin 中的平均元素数大于此阈值时,可能要重新调整大小。 * @param concurrencyLevel 当前更新线程的估计数。该实现将执行内部大小调整,以尽量容纳这些线程。 */ public ConcurrentReferenceMap(ReferenceKeyType keyReferenceType, ReferenceValueType valueReferenceType, int initialCapacity, float loadFactor, int concurrencyLevel) { this.keyReferenceType = keyReferenceType; this.valueReferenceType = valueReferenceType; this.concurrencyLevel = concurrencyLevel; this.initialCapacity = initialCapacity; this.loadFactor = loadFactor; this.map = new ConcurrentHashMap<Object, Object>(initialCapacity, loadFactor, concurrencyLevel); } @SuppressWarnings("unchecked") @Override public Set<K> keySet() { if (this.keyReferenceType == ReferenceKeyType.STRONG) { // 如果为强引用,则 map 中的 keySet 就是需要的 return (Set<K>) this.map.keySet(); } // 为其他引用 return new AbstractSet<K>() { public Iterator<K> iterator() { return new Iterator<K>() { private Iterator<Object> iterator = ConcurrentReferenceMap.this.map.keySet().iterator(); public boolean hasNext() { return this.iterator.hasNext(); } public K next() { return getKey(this.iterator.next()); } public void remove() { this.iterator.remove(); } }; } public int size() { return ConcurrentReferenceMap.this.map.size(); } }; } @Override public void clear() { this.map.clear(); } @Override public V remove(Object key) { notNull(key); Object keyReference = createKeyReferenceWrapper(key); Object returnValueReference = this.map.remove(keyReference); return getValue(returnValueReference); } @Override public boolean containsKey(Object key) { return this.map.containsKey(key); } @Override public int size() { return this.map.size(); } @Override public boolean isEmpty() { return this.map.isEmpty(); } @SuppressWarnings("unchecked") private V getValue(Object valueReference) { return (V) (this.valueReferenceType == ReferenceValueType.STRONG ? valueReference : valueReference == null ? null : ((Reference<V>) valueReference).get()); } @SuppressWarnings("unchecked") private K getKey(Object keyReference) { return (K) (this.keyReferenceType == ReferenceKeyType.STRONG ? keyReference : keyReference == null ? null : ((Reference<K>) keyReference).get()); } /** * 创建 Key 的印射包装器。 * @param key 要创建印射包装器的 key。 * @return 如果是强引用,返回 key 本身,否则返回 Key 的印射包装器。 */ private Object createKeyReferenceWrapper(Object key) { return this.keyReferenceType == ReferenceKeyType.STRONG ? key : new KeyReferenceWrapper(key); } /** * 创建 Value 的印射包装器。 * @param value 要创建印射包装器的 value。 * @return 如果是强引用,返回 value 本身,否则返回 Value 的印射包装器。 */ private Object createValueReferenceWrapper(Object value) { return this.valueReferenceType == ReferenceValueType.STRONG ? value : new ValueReferenceWrapper(value); } /** * 得到 key 在内存中的地址的 hashCode。 * @param key 要得到在内存中的地址的 hashCode 的 key。 * @return key 在内存中的地址的 hashCode。 * @see System#identityHashCode(Object) */ private int keyHashCode(Object key) { return System.identityHashCode(key); } private boolean referenceEquals(Reference<?> reference, Object object) { if (reference == object) { // 直接引用相同 return true; } if (reference == null) { // 一方为 null 则返回 false(因为上个判断结合这个判断,object 一定不为 null) return false; } if (object instanceof Reference<?>) { // object 为引用类型,则比较引用类型中的值的引用 Object referenceValue = ((Reference<?>) object).get(); return referenceValue != null && reference.get() == referenceValue; } if (object instanceof ReferenceWrapper) { // object为 引用包装类型 return ((ReferenceWrapper) object).getReference() == reference.get(); } return false; } @Override public V get(Object key) { notNull(key); Object keyReference = createKeyReferenceWrapper(key); Object returnValueReference = this.map.get(keyReference); return getValue(returnValueReference); } @Override public V put(K key, V value) { notNull(key); notNull(value); Object keyReference = wrapKey(key); Object valueReference = wrapValue(keyReference, value); Object returnValueReference = this.map.put(keyReference, valueReference); if (returnValueReference == null) { return null; } return getValue(returnValueReference); } public V putIfAbsent(K key, V value) { notNull(key); notNull(value); Object keyReference = wrapKey(key); Object valueReference = wrapValue(keyReference, value); Object returnValueReference = this.map.putIfAbsent(keyReference, valueReference); if (returnValueReference == null) { return null; } return getValue(returnValueReference); } public boolean remove(Object key, Object value) { notNull(key); Object keyReference = createKeyReferenceWrapper(key); Object valueReference = createValueReferenceWrapper(value); return this.map.remove(keyReference, valueReference); } public boolean replace(K key, V oldValue, V newValue) { notNull(key); notNull(oldValue); notNull(newValue); Object keyReference = wrapKey(key); Object oldValueReference = createValueReferenceWrapper(oldValue); Object valueReference = wrapValue(keyReference, newValue); return this.map.replace(keyReference, oldValueReference, valueReference); } public V replace(K key, V value) { notNull(key); notNull(value); Object keyReference = wrapKey(key); Object valueReference = wrapValue(keyReference, value); Object returnValueReference = this.map.replace(keyReference, valueReference); if (returnValueReference == null) { return null; } return getValue(returnValueReference); } private Object wrapKey(K key) { Object keyReference = null; switch (this.keyReferenceType) { case STRONG: keyReference = key; break; case SOFT: keyReference = new FinalizableKeySoftReference<K>(key); break; case WEAK: keyReference = new FinalizableKeyWeakReference<K>(key); break; case PHANTOM: keyReference = new FinalizableKeyPhantomReference<K>(key); break; } return keyReference; } private Object wrapValue(Object keyReference, V value) { Object valueReference = null; switch (this.valueReferenceType) { case STRONG: valueReference = value; break; case SOFT: valueReference = new FinalizableValueSoftReference<V>(keyReference ,value); break; case WEAK: valueReference = new FinalizableValueWeakReference<V>(keyReference ,value); break; case PHANTOM: valueReference = new FinalizableValuePhantomReference<V>(keyReference ,value); break; } return valueReference; } public Set<Entry<K, V>> entrySet() { return new AbstractSet<Entry<K, V>>() { public Iterator<Entry<K, V>> iterator() { return new Iterator<Entry<K, V>>() { private Iterator<Entry<Object, Object>> iterator = ConcurrentReferenceMap.this.map.entrySet().iterator(); public boolean hasNext() { return this.iterator.hasNext(); } public Entry<K, V> next() { final Entry<Object, Object> entry = this.iterator.next(); return new Entry<K, V>() { public K getKey() { return ConcurrentReferenceMap.this.getKey(entry.getKey()); } public V getValue() { return ConcurrentReferenceMap.this.getValue(entry.getValue()); } public V setValue(V value) { throw new UnsupportedOperationException("不支持的操作。"); } }; } public void remove() { this.iterator.remove(); } }; } public int size() { return ConcurrentReferenceMap.this.map.size(); } }; } /** * 弱引用对象的键类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableKeyWeakReference<T> extends FinalizableWeakReference<T> implements FinalizableReference<T> { private final int hashCode; /** * 构造一个新的 弱引用对象的键类 实例。 * @param referent 键。 */ protected FinalizableKeyWeakReference(T referent) { super(referent, FINALIZABLE_REFERENCE_QUEUE); this.hashCode = keyHashCode(referent); } public void finalizeReferent() { ConcurrentReferenceMap.this.map.remove(this); } @Override public int hashCode() { return this.hashCode; } @Override public boolean equals(Object object) { return referenceEquals(this, object); } } /** * 弱引用对象的值类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableValueWeakReference<T> extends FinalizableWeakReference<T> implements FinalizableReference<T> { private Object keyReference; /** * 构造一个新的 弱引用对象的值类 实例。 * @param keyReference 与此值关联的 键 。 * @param referent 值。 */ protected FinalizableValueWeakReference(Object keyReference, T referent) { super(referent, FINALIZABLE_REFERENCE_QUEUE); this.keyReference = keyReference; } public void finalizeReferent() { ConcurrentReferenceMap.this.map.remove(this.keyReference, this); } @Override public int hashCode() { T v = get(); return v == null ? 0 : v.hashCode(); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (this == obj) { return true; } if (!(obj instanceof ConcurrentReferenceMap<?, ?>.FinalizableValueWeakReference<?>)) { return false; } T v = get(); Object objV = ((FinalizableValueWeakReference<?>) obj).get(); if (v == null) { if (v == objV) { return true; } } return v.equals(objV); } } /** * 软引用对象的键类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableKeySoftReference<T> extends FinalizableSoftReference<T> implements FinalizableReference<T> { private final int hashCode; /** * 构造一个新的 软引用对象的键类 实例。 * @param referent 键。 */ protected FinalizableKeySoftReference(T referent) { super(referent, FINALIZABLE_REFERENCE_QUEUE); this.hashCode = keyHashCode(referent); } public void finalizeReferent() { ConcurrentReferenceMap.this.map.remove(this); } @Override public int hashCode() { return this.hashCode; } @Override public boolean equals(Object object) { return referenceEquals(this, object); } } /** * 软引用对象的值类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableValueSoftReference<T> extends FinalizableSoftReference<T> implements FinalizableReference<T> { private Object keyReference; /** * 构造一个新的 软引用对象的值类 实例。 * @param keyReference 与此值关联的 键 。 * @param referent 值。 */ protected FinalizableValueSoftReference(Object keyReference ,T referent) { super(referent, FINALIZABLE_REFERENCE_QUEUE); this.keyReference = keyReference; } public void finalizeReferent() { ConcurrentReferenceMap.this.map.remove(this.keyReference, this); } @Override public int hashCode() { T v = get(); return v == null ? 0 : v.hashCode(); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (this == obj) { return true; } if (!(obj instanceof ConcurrentReferenceMap<?, ?>.FinalizableValueSoftReference<?>)) { return false; } T v = get(); Object objV = ((FinalizableValueSoftReference<?>) obj).get(); if (v == null) { if (v == objV) { return true; } } return v.equals(objV); } } /** * 虚引用对象的键类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableKeyPhantomReference<T> extends FinalizablePhantomReference<T> implements FinalizableReference<T> { private final int hashCode; /** * 构造一个新的 虚引用对象的键类 实例。 * @param referent 键。 */ protected FinalizableKeyPhantomReference(T referent) { super(referent, FINALIZABLE_REFERENCE_QUEUE); this.hashCode = keyHashCode(referent); } public void finalizeReferent() { ConcurrentReferenceMap.this.map.remove(this); } @Override public int hashCode() { return this.hashCode; } @Override public boolean equals(Object object) { return referenceEquals(this, object); } } /** * 虚引用对象的值类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableValuePhantomReference<T> extends FinalizablePhantomReference<T> implements FinalizableReference<T> { private Object keyReference; /** * 构造一个新的 虚引用对象的值类 实例。 * @param keyReference 与此值关联的 键 。 * @param referent 值。 */ protected FinalizableValuePhantomReference(Object keyReference ,T referent) { super(referent, FINALIZABLE_REFERENCE_QUEUE); this.keyReference = keyReference; } public void finalizeReferent() { ConcurrentReferenceMap.this.map.remove(this.keyReference, this); } @Override public int hashCode() { return 0; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (this == obj) { return true; } if (!(obj instanceof ConcurrentReferenceMap<?, ?>.FinalizableValuePhantomReference<?>)) { return false; } Object v = ((FinalizableValuePhantomReference<?>) obj).get(); if (v == null) { return true; } return v.equals(get()); } } /** * 引用类型中的对象的另一个包装器,该包装器实现为引用类型中的对象保持 put 与 get 时用到的 hashCode 和 equals 方法的一致性。 * @author <a href="http://www.agrael.cn">李翔</a> * */ protected static class ReferenceWrapper { protected final Object reference; /** * 使用一个引用类型中的对象实例构造一个新的包装器。 * @param reference 要包装的引用类型中的对象实例。 */ protected ReferenceWrapper(Object reference) { this.reference = reference; } /** * 得到被包装的对象。 * @return 被包装的对象。 */ protected Object getReference() { return this.reference; } /** * 调用包装对象的 hashCode 方法。 * @return 包装对象的 hashCode。 */ @Override public int hashCode() { return this.reference.hashCode(); } /** * 调用包装对象的 equals 方法比较。 * @param obj 要与之比较的对象。 * @return 如果传入的对象和包装对象“相等”则返回 true,否则返回 false。 */ @Override public boolean equals(Object obj) { // 使用包装对象的 equals return obj.equals(this); } } /** * 专用于 key 的引用类型中的对象的另一个包装器。该包装器重写了 hashCode 方法,使用 {@link System#identityHashCode(Object)} 取得 hash值 。 * @author <a href="http://www.agrael.cn">李翔</a> * */ protected static class KeyReferenceWrapper extends ReferenceWrapper { /** * 使用一个引用类型中的 key对象实例 构造一个新的包装器。 * @param reference 要包装的引用类型中的key对象实例。 */ protected KeyReferenceWrapper(Object reference) { super(reference); } /** * 返回包装的 Key 的内存里的 hashCode。 * @return 包装的 Key 的内存里的 hashCode。 * @see System#identityHashCode(Object) */ @Override public int hashCode() { // 这里要认为同一内存地址的才是相同对象,所以取得内存地址中的 HASH码 return System.identityHashCode(this.reference); } } /** * 专用于 value 的引用类型中的对象的另一个包装器。该包装器重写了 hashCode 方法,使用 {@link System#identityHashCode(Object)} 取得 hash值 。 * @author <a href="http://www.agrael.cn">李翔</a> * */ protected static class ValueReferenceWrapper extends ReferenceWrapper { /** * 使用一个引用类型中的 key对象实例 构造一个新的包装器。 * @param reference 要包装的引用类型中的key对象实例。 */ protected ValueReferenceWrapper(Object reference) { super(reference); } } /** * 用作 K 的引用类型。 * @author <a href="http://www.agrael.cn">李翔</a> * */ public static enum ReferenceKeyType { /** 强引用 */ STRONG, /** 软引用 */ SOFT, /** 弱引用 */ WEAK, /** 虚引用 */ PHANTOM; } /** * 用作 V 的引用类型。 * @author <a href="http://www.agrael.cn">李翔</a> * */ public static enum ReferenceValueType { /** 强引用 */ STRONG, /** 软引用 */ SOFT, /** 弱引用 */ WEAK, /** 虚引用 */ PHANTOM; } static void notNull(Object obj) { if (obj == null) { throw new NullPointerException(); } } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(size()); out.writeFloat(this.loadFactor); out.writeInt(this.concurrencyLevel); out.writeInt(this.initialCapacity); for (Map.Entry<Object, Object> entry : this.map.entrySet()) { Object key = getKey(entry.getKey()); Object value = getValue(entry.getValue()); if (key != null && value != null) { out.writeObject(key); out.writeObject(value); } } out.writeObject(null); } @SuppressWarnings("unchecked") private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); int size = in.readInt(); float loadFactor = in.readFloat(); int concurrencyLevel = in.readInt(); int initialCapacity = in.readInt(); this.loadFactor = loadFactor; this.concurrencyLevel = concurrencyLevel; this.initialCapacity = initialCapacity; this.map = new ConcurrentHashMap<Object, Object>(size, loadFactor, concurrencyLevel); while (true) { K key = (K) in.readObject(); if (key == null) { break; } V value = (V) in.readObject(); put(key, value); } } }
其中最后那2个枚举为ConcurrentReferenceMap的 key 与 value 引用类型的枚举,在构造 ConcurrentReferenceMap时,使用该枚举即可创建想要的引用类型的ConcurrentReferenceMap。
以下是一个示例:
public static void main(String[] args) throws Exception { ConcurrentMap<Object, Object> referenceMap = new ConcurrentReferenceMap<Object, Object>(ReferenceKeyType.WEAK, ReferenceValueType.WEAK); Object key = new Object(); Object value = new Object(); referenceMap.put(key, value); System.out.println(referenceMap.isEmpty()); // 返回 false // 由于是弱引用,所以将 key 或者 value 其中某一个 设置为 null 都可触发清除 key = null; // 将 key 消除强引用 //value = null; // 或者注释上面一行将该行取消注释,将 value 消除强引用 System.gc(); TimeUnit.SECONDS.sleep(5); System.out.println(referenceMap.isEmpty()); // 返回true,证明已经被清除,这期间不需要像WeakHashMap一样操作后才清除,并且保证并发安全 }
最后完整的代码在附件里。
现在已经修改为实现ConcurrentMap接口。
- ConcurrentReferenceMap源码.rar (9 KB)
- 下载次数: 60
评论
使用Reference类实际是想让一个实例对象(Object)进行资源内存回收,但是,自己本身也创建了
WeakReference实例对象(比如new WeakReference(...)),这个WeakReference实例对象同样占用内存,
有此可推出,通过一个新建WeakReference象(内存创建)来回收一个实例对象(Object内存回收),这符合常理吗?还望赐教。
JVM对Reference是特殊处理的。
能否再具体点?谢谢
这个还不是太好举,这样吧,你看看Reference这个类中有一行。
private T referent; /* Treated specially by GC */
这个本来是强引用属于,但是旁边的注释说明,虚拟机会特殊对待这个引用。所以在Reference这个实例的引用还在的时候,里面的这个private T referent;才可以被回收。
当然这个只是一方面。
使用Reference类实际是想让一个实例对象(Object)进行资源内存回收,但是,自己本身也创建了
WeakReference实例对象(比如new WeakReference(...)),这个WeakReference实例对象同样占用内存,
有此可推出,通过一个新建WeakReference象(内存创建)来回收一个实例对象(Object内存回收),这符合常理吗?还望赐教。
JVM对Reference是特殊处理的。
能否再具体点?谢谢
使用Reference类实际是想让一个实例对象(Object)进行资源内存回收,但是,自己本身也创建了
WeakReference实例对象(比如new WeakReference(...)),这个WeakReference实例对象同样占用内存,
有此可推出,通过一个新建WeakReference象(内存创建)来回收一个实例对象(Object内存回收),这符合常理吗?还望赐教。
JVM对Reference是特殊处理的。
使用Reference类实际是想让一个实例对象(Object)进行资源内存回收,但是,自己本身也创建了
WeakReference实例对象(比如new WeakReference(...)),这个WeakReference实例对象同样占用内存,
有此可推出,通过一个新建WeakReference象(内存创建)来回收一个实例对象(Object内存回收),这符合常理吗?还望赐教。
代码如下:
//Create an object MyObject obj = new MyObject(); System.out.println("object is " + obj); //Create a reference queue ReferenceQueue rq = new ReferenceQueue(); //Create a weakReference to obj and associate our reference queue PhantomReference wr = new PhantomReference(obj, rq); obj = null; System.out.println("The weak reference is " + wr); System.gc(); Thread.sleep(10000); System.out.println("Polling the reference queue returns " + rq.remove()); System.out.println("Getting the referent from the " + "phantom reference returns " + wr.get());
由以上现象推测LZ的代码中,是否也可能会产生一直阻塞的现象?
remove方法会从调用时阻塞到有Reference中的对象被回收。
你的代码中是已经回收后再remove,之后并没有Reference中的对象被回收,所以回一直阻塞。
代码如下:
//Create an object MyObject obj = new MyObject(); System.out.println("object is " + obj); //Create a reference queue ReferenceQueue rq = new ReferenceQueue(); //Create a weakReference to obj and associate our reference queue PhantomReference wr = new PhantomReference(obj, rq); obj = null; System.out.println("The weak reference is " + wr); System.gc(); Thread.sleep(10000); System.out.println("Polling the reference queue returns " + rq.remove()); System.out.println("Getting the referent from the " + "phantom reference returns " + wr.get());
由以上现象推测LZ的代码中,是否也可能会产生一直阻塞的现象?
如果我没有理解错的话,你的思路就是,Daemon线程在不停“GC”(你这里的finalizeReferent)非强引用,不过JVM启动的时候,有一个Finalizer的线程在执行。
这里有几个问题:
1.三种非强引用的生命周期不同,软引用是在内存不足的情况被清理,弱引用是在对象不在关联,幻想的话,是已经被GC掉了。
2.ReferenceMap实现中,保存全部的是强引用对象,程序中并不能确定合适清理。
3.因为第2点,会产生内存泄漏。
4.命名,加一个Concurrent吧。
首先感谢你对帖子的关注。
1、是的,已经被GC清理掉了,但是在清理后,一直阻塞的ReferenceQueue的remove方法会返回当前被清理的对象的Reference的引用。实际这个时候Reference里的对象已经为null(被清理)。但是在这里我们并不会用到那个对象,而是使用的实现了FinalizableReference的Reference的清理方法finalizeReferent。以FinalizableKeyWeakReference来说,它的finalizeReferent方法为:
public void finalizeReferent() { map.remove(this); }
可以看到,在这里已经从map中移除了自身在包装的ConcurrentHashMap中的印射关系。
2、由于1的结论,在key/value的对象被清理时,实际已经从该Map中清除关系了。
3、由于回答2的原因,内存泄漏问题得到解决。
4、谢谢这个,非常好的提议:)
你的东西是一个很好的实践,为什么我这么说?
当年Doug Lea写的java.util.concurrent.locks.AbstractQueuedSynchronizer 能够通过编程的方法实现synchronized,虽然离不开JVM的本地方法,但是也是一种很好的设计。
题外话,我很欣赏楼主,呵呵,因为我也这样的人,喜欢重复发明轮子,为什么不能?
呵呵,其实我还比较喜欢发明轮子的。其实看看现在的开源框架,是否一个又一个轮子呢?
勇于创造,才有创新,凭空不能想象出伟大。
这句话太有哲理性了,朋友也是喜欢写自己的东西的,不知道对JAAS的了解如何?我想探讨下关于JAAS在应用服务器中自定义LoginModule的问题。
如果我没有理解错的话,你的思路就是,Daemon线程在不停“GC”(你这里的finalizeReferent)非强引用,不过JVM启动的时候,有一个Finalizer的线程在执行。
这里有几个问题:
1.三种非强引用的生命周期不同,软引用是在内存不足的情况被清理,弱引用是在对象不在关联,幻想的话,是已经被GC掉了。
2.ReferenceMap实现中,保存全部的是强引用对象,程序中并不能确定合适清理。
3.因为第2点,会产生内存泄漏。
4.命名,加一个Concurrent吧。
首先感谢你对帖子的关注。
1、是的,已经被GC清理掉了,但是在清理后,一直阻塞的ReferenceQueue的remove方法会返回当前被清理的对象的Reference的引用。实际这个时候Reference里的对象已经为null(被清理)。但是在这里我们并不会用到那个对象,而是使用的实现了FinalizableReference的Reference的清理方法finalizeReferent。以FinalizableKeyWeakReference来说,它的finalizeReferent方法为:
public void finalizeReferent() { map.remove(this); }
可以看到,在这里已经从map中移除了自身在包装的ConcurrentHashMap中的印射关系。
2、由于1的结论,在key/value的对象被清理时,实际已经从该Map中清除关系了。
3、由于回答2的原因,内存泄漏问题得到解决。
4、谢谢这个,非常好的提议:)
你的东西是一个很好的实践,为什么我这么说?
当年Doug Lea写的java.util.concurrent.locks.AbstractQueuedSynchronizer 能够通过编程的方法实现synchronized,虽然离不开JVM的本地方法,但是也是一种很好的设计。
题外话,我很欣赏楼主,呵呵,因为我也这样的人,喜欢重复发明轮子,为什么不能?
呵呵,其实我还比较喜欢发明轮子的。其实看看现在的开源框架,是否一个又一个轮子呢?
勇于创造,才有创新,凭空不能想象出伟大。
如果我没有理解错的话,你的思路就是,Daemon线程在不停“GC”(你这里的finalizeReferent)非强引用,不过JVM启动的时候,有一个Finalizer的线程在执行。
这里有几个问题:
1.三种非强引用的生命周期不同,软引用是在内存不足的情况被清理,弱引用是在对象不在关联,幻想的话,是已经被GC掉了。
2.ReferenceMap实现中,保存全部的是强引用对象,程序中并不能确定合适清理。
3.因为第2点,会产生内存泄漏。
4.命名,加一个Concurrent吧。
首先感谢你对帖子的关注。
1、是的,已经被GC清理掉了,但是在清理后,一直阻塞的ReferenceQueue的remove方法会返回当前被清理的对象的Reference的引用。实际这个时候Reference里的对象已经为null(被清理)。但是在这里我们并不会用到那个对象,而是使用的实现了FinalizableReference的Reference的清理方法finalizeReferent。以FinalizableKeyWeakReference来说,它的finalizeReferent方法为:
public void finalizeReferent() { map.remove(this); }
可以看到,在这里已经从map中移除了自身在包装的ConcurrentHashMap中的印射关系。
2、由于1的结论,在key/value的对象被清理时,实际已经从该Map中清除关系了。
3、由于回答2的原因,内存泄漏问题得到解决。
4、谢谢这个,非常好的提议:)
你的东西是一个很好的实践,为什么我这么说?
当年Doug Lea写的java.util.concurrent.locks.AbstractQueuedSynchronizer 能够通过编程的方法实现synchronized,虽然离不开JVM的本地方法,但是也是一种很好的设计。
题外话,我很欣赏楼主,呵呵,因为我也这样的人,喜欢重复发明轮子,为什么不能?
呵呵,其实我还比较喜欢发明轮子的。其实看看现在的开源框架,是否一个又一个轮子呢?
如果我没有理解错的话,你的思路就是,Daemon线程在不停“GC”(你这里的finalizeReferent)非强引用,不过JVM启动的时候,有一个Finalizer的线程在执行。
这里有几个问题:
1.三种非强引用的生命周期不同,软引用是在内存不足的情况被清理,弱引用是在对象不在关联,幻想的话,是已经被GC掉了。
2.ReferenceMap实现中,保存全部的是强引用对象,程序中并不能确定合适清理。
3.因为第2点,会产生内存泄漏。
4.命名,加一个Concurrent吧。
首先感谢你对帖子的关注。
1、是的,已经被GC清理掉了,但是在清理后,一直阻塞的ReferenceQueue的remove方法会返回当前被清理的对象的Reference的引用。实际这个时候Reference里的对象已经为null(被清理)。但是在这里我们并不会用到那个对象,而是使用的实现了FinalizableReference的Reference的清理方法finalizeReferent。以FinalizableKeyWeakReference来说,它的finalizeReferent方法为:
public void finalizeReferent() { map.remove(this); }
可以看到,在这里已经从map中移除了自身在包装的ConcurrentHashMap中的印射关系。
2、由于1的结论,在key/value的对象被清理时,实际已经从该Map中清除关系了。
3、由于回答2的原因,内存泄漏问题得到解决。
4、谢谢这个,非常好的提议:)
你的东西是一个很好的实践,为什么我这么说?
当年Doug Lea写的java.util.concurrent.locks.AbstractQueuedSynchronizer 能够通过编程的方法实现synchronized,虽然离不开JVM的本地方法,但是也是一种很好的设计。
题外话,我很欣赏楼主,呵呵,因为我也这样的人,喜欢重复发明轮子,为什么不能?
如果我没有理解错的话,你的思路就是,Daemon线程在不停“GC”(你这里的finalizeReferent)非强引用,不过JVM启动的时候,有一个Finalizer的线程在执行。
这里有几个问题:
1.三种非强引用的生命周期不同,软引用是在内存不足的情况被清理,弱引用是在对象不在关联,幻想的话,是已经被GC掉了。
2.ReferenceMap实现中,保存全部的是强引用对象,程序中并不能确定合适清理。
3.因为第2点,会产生内存泄漏。
4.命名,加一个Concurrent吧。
首先感谢你对帖子的关注。
1、是的,已经被GC清理掉了,但是在清理后,一直阻塞的ReferenceQueue的remove方法会返回当前被清理的对象的Reference的引用。实际这个时候Reference里的对象已经为null(被清理)。但是在这里我们并不会用到那个对象,而是使用的实现了FinalizableReference的Reference的清理方法finalizeReferent。以FinalizableKeyWeakReference来说,它的finalizeReferent方法为:
public void finalizeReferent() { map.remove(this); }
可以看到,在这里已经从map中移除了自身在包装的ConcurrentHashMap中的印射关系。
2、由于1的结论,在key/value的对象被清理时,实际已经从该Map中清除关系了。
3、由于回答2的原因,内存泄漏问题得到解决。
4、谢谢这个,非常好的提议:)
如果我没有理解错的话,你的思路就是,Daemon线程在不停“GC”(你这里的finalizeReferent)非强引用,不过JVM启动的时候,有一个Finalizer的线程在执行。
这里有几个问题:
1.三种非强引用的生命周期不同,软引用是在内存不足的情况被清理,弱引用是在对象不在关联,幻想的话,是已经被GC掉了。
2.ReferenceMap实现中,保存全部的是强引用对象,程序中并不能确定合适清理。
3.因为第2点,会产生内存泄漏。
4.命名,加一个Concurrent吧。
value的引用会有这样的场景。例如Class
此外我不明白什么叫做 value 也需要引用?我好奇有这种场景应用么?
<p>第二个是在《<a href="/topic/670414" target="_blank">Google
Collections中强大的Concurrent MapMaker</a>》</p>
<p> </p>
发表评论
-
【闲暇】使用中文写java代码
2010-07-20 13:40 2972该帖的目的仅仅为了好玩,现实开发中还是规范来的好。 不过倒是可 ... -
不要同时使用ReentrantLock类与synchronized关键字锁定会修改同一个资源的不同方法
2010-06-07 12:08 3297本文是讲述Reentrant ... -
通过struts2-ejb3-plugin把Struts2与EJB3.0无缝整合起来
2010-04-16 09:28 3133本文是讲述使用struts2-ejb3-plu ... -
非阻塞算法-ReentrantLock代码剖析之ReentrantLock.lock
2010-03-24 11:05 1898ReentrantLock是java.util.concurr ...
相关推荐
哈希映射(HashMap)是Java编程语言中一个非常重要的数据结构,它在《简单的key value hashmap》中被提及,通常用于存储键值对(key-value pairs)。HashMap是Java集合框架的一部分,它提供了高效的查找、插入和删除...
与传统的`Hashtable`相比,`ConcurrentHashMap`具有更高的并发性能,这主要得益于它的分段锁技术和非阻塞算法。 #### 二、`ConcurrentHashMap`的基本概念 1. **分段锁技术**:`ConcurrentHashMap`内部采用了分段锁...
ConcurrentHashMap#put方法源码解析 ConcurrentHashMap是Java并发编程中的一个重要组件,用于解决高并发情况下的数据存储问题。在面试中,ConcurrentHashMap的底层原理、put方法的实现细节都是高频考点。本文将对...
其中,`key`和`hash`字段用于存储键和计算后的哈希值,`value`字段用于存储值,而`next`字段则用于连接同一个`Segment`中的多个`HashEntry`形成链表。 **3. 扩容机制** 当一个`Segment`中的元素数量达到一定阈值时...
Node 是 ConcurrentHashMap 中的一个基本组件,保存 key,value 及 key 的 hash 值的数据结构,其中 value 和 next 都用 volatile 修饰,保证并发的可见性。 JDK8 中 ConcurrentHashMap 的结构由于引入了红黑树,...
HashMap& ConcurrentHashMap 深度解析
java本地缓存ConcurrentHashMap
在JDK 1.8版本中,`ConcurrentHashMap`中的`computeIfAbsent`方法存在一个潜在的死循环问题。这个bug主要出现在并发操作时,当`ConcurrentHashMap`需要进行扩容并且`computeIfAbsent`正在执行计算的过程中,可能会...
Java中遍历ConcurrentHashMap的四种方式详解 Java中遍历ConcurrentHashMap的四种方式详解是Java开发中一个非常重要的知识点。ConcurrentHashMap是Java中一种高效且线程安全的HashMap实现,它提供了高效的读写操作...
程序员面试加薪必备_ConcurrentHashMap底层原理与源码分析深入详解
### HashMap和ConcurrentHashMap面试要点详解 #### HashMap面试要点 ##### HashMap底层数据结构 **JDK7与JDK8的差异:** - **JDK7的HashMap**底层是由数组+链表构成的。在JDK7中,链表采用头插法(head-...
与传统的HashMap相比,ConcurrentHashMap在多线程环境下具有更好的性能,尤其是在读多写少的场景下。它通过引入锁分段技术解决了并发环境下效率低下的问题。 首先,我们来了解什么是线程安全的HashMap。HashMap在单...
如果链表中存在与`key`相同的节点,那么更新节点的`value`,否则创建新的`HashEntry`对象并插入链表头部。 `put`方法中的`scanAndLockForPut`方法用于处理获取锁的逻辑。它采用循环尝试获取锁,同时检查链表是否有...
在Java 7中,HashMap的内部结构主要由一个Entry数组组成,每个Entry包含key、value、hash值和指向下一个Entry的引用。HashMap的put过程主要包括以下几个步骤: 1. 计算key的哈希值hash。 2. 根据数组长度和哈希值...
Map,也常被称为哈希表或字典,是数据结构中的一种重要类型,它允许我们通过键(key)来快速查找、添加和删除对应的值(value)。在各种编程语言中,如Java、C++、Python等,都有内置的Map实现。 Map的基本工作原理...
Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~
Java并发编程中的ConcurrentHashMap是HashMap的一个线程安全版本,设计目标是在高并发场景下提供高效的数据访问。相比HashTable,ConcurrentHashMap通过采用锁分离技术和更细粒度的锁定策略来提升性能。HashTable...