该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-05-21
恩,没问题的。一会我单独开个帖子,发个完整的。
package cn.agrael.collection; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; 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.FinalizableSoftReference; import cn.agrael.ref.FinalizableWeakReference; import cn.agrael.util.Assert; /** * 支持各种引用类型的 Map。 * <p> * 引用类型请参考 {@link java.lang.ref}与 {@link cn.agrael.ref} 的描述。 * </p> * <p> * 该 Map 的特性和 {@link ConcurrentHashMap} 一样。在第一次调用 put/putAll * 方法时(仅仅是在同一个类加载器中的第一次 * ,如果为同一类加载器,那么在put/putAll后,新创建的实例的put/putAll也不算做第一次),会有一个后台线程随之创建并启动 * ,该后台线程主要作用和垃圾回收交互,进行回收对象的清理。在清理 键 * 的同时,会一同清理掉 键的引用包装器 以及 值 和 值的引用包装器 以及 印射 ,在清理 值 时 ,会一同清理掉 值的引用包装器,然后从 Map 中移除印射到自身的 键 以及 印射 。 * </p> * <p> * 该清理是 异步 且 “即时” 的,会在垃圾回收的同时清理,不需要在下次对该 Map 操作时才清理包装引用的实例。 * </p> * * @author <a href="http://www.agrael.cn">李翔</a> * * @param <K> * 此映射维护的键类型 * @param <V> * 映射值的类型 */ public class ReferenceMap<K, V> extends AbstractMap<K, V> implements Map<K, V> { /** 版本号 */ private static final long serialVersionUID = -6254917146703219097L; 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 ReferenceMap(ReferenceKeyType keyReferenceType ,ReferenceValueType valueReferenceType) { this.keyReferenceType = keyReferenceType; this.valueReferenceType = valueReferenceType; map = new ConcurrentHashMap<Object, Object>(initialCapacity,loadFactor,concurrencyLevel); } /** * 通过指定的 key引用类型 和 value引用类型 创建一个带有指定初始容量、默认加载因子和 concurrencyLevel 的新的空映射。 * @param keyReferenceType key引用类型。 * @param valueReferenceType value引用类型。 * @param initialCapacity 初始容量。该实现执行内部大小调整,以容纳这些元素。 */ public ReferenceMap(ReferenceKeyType keyReferenceType ,ReferenceValueType valueReferenceType, int initialCapacity) { this.keyReferenceType = keyReferenceType; this.valueReferenceType = valueReferenceType; this.initialCapacity = initialCapacity; map = new ConcurrentHashMap<Object, Object>(initialCapacity,loadFactor,concurrencyLevel); } /** * 通过指定的 key引用类型 和 value引用类型 创建一个带有指定初始容量、加载因子和并发级别的新的空映射。 * @param keyReferenceType key引用类型。 * @param valueReferenceType value引用类型。 * @param initialCapacity 初始容量。该实现执行内部大小调整,以容纳这些元素。 * @param loadFactor 加载因子阈值,用来控制重新调整大小。在每 bin 中的平均元素数大于此阈值时,可能要重新调整大小。 * @param concurrencyLevel 当前更新线程的估计数。该实现将执行内部大小调整,以尽量容纳这些线程。 */ public ReferenceMap(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; map = new ConcurrentHashMap<Object, Object>(initialCapacity, loadFactor, concurrencyLevel); } @SuppressWarnings("unchecked") @Override public Set<K> keySet() { if(keyReferenceType == ReferenceKeyType.STRONG){ // 如果为强引用,则 map 中的 keySet 就是需要的 return (Set<K>) map.keySet(); } // 为其他引用 return new AbstractSet<K>() { public Iterator<K> iterator() { return new Iterator<K>() { private Iterator<Object> iterator = map.keySet().iterator(); public boolean hasNext() { return iterator.hasNext(); } public K next() { return getKey(iterator.next()); } public void remove() { iterator.remove(); } }; } public int size() { return map.size(); } }; } @Override public void clear() { map.clear(); } @Override public V remove(Object key) { Assert.notNull(key); Object keyReference = createKeyReferenceWrapper(key); Object returnValueReference = map.remove(keyReference); return getValue(returnValueReference); } @Override public boolean containsKey(Object key) { return map.containsKey(key); } @Override public int size() { return map.size(); } @Override public boolean isEmpty() { return map.isEmpty(); } @Override public V put(K key, V value) { Assert.notNull(key); Assert.notNull(value); Object keyReference = null; switch (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; } Object valueReference = null; switch (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; } Object returnValueReference = map.put(keyReference, valueReference); if(returnValueReference == null){ return null; } return getValue(returnValueReference); } @SuppressWarnings("unchecked") private V getValue(Object valueReference){ return (V) (valueReferenceType == ReferenceValueType.STRONG ? valueReference : valueReference == null ? null : ((Reference<V>) valueReference).get()); } @SuppressWarnings("unchecked") private K getKey(Object keyReference){ return (K) (keyReferenceType == ReferenceKeyType.STRONG ? keyReference : keyReference == null ? null : ((Reference<K>) keyReference).get()); } /** * 创建 Key 的印射包装器。 * @param key 要创建印射包装器的 key。 * @return 如果是强引用,返回 key 本身,否则返回 Key 的印射包装器。 */ private Object createKeyReferenceWrapper(Object key){ return keyReferenceType == ReferenceKeyType.STRONG ? key : new KeyReferenceWrapper(key); } /** * 得到 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 KeyReferenceWrapper){ // object为 key 引用包装类型 return ((KeyReferenceWrapper) object).getReference() == reference.get(); } return false; } @Override public V get(Object key) { Assert.notNull(key); Object keyReference = createKeyReferenceWrapper(key); Object returnValueReference = map.get(keyReference); return getValue(returnValueReference); } 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 = map.entrySet().iterator(); public boolean hasNext() { return iterator.hasNext(); } public Entry<K, V> next() { final Entry<Object, Object> entry = iterator.next(); return new Entry<K, V>() { public K getKey() { return ReferenceMap.this.getKey(entry.getKey()); } public V getValue() { return ReferenceMap.this.getValue(entry.getValue()); } public V setValue(V value) { throw new UnsupportedOperationException("不支持的操作。"); } }; } public void remove() { iterator.remove(); } }; } public int size() { return 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); 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); } } /** * 引用类型中的对象的另一个包装器,该包装器实现为引用类型中的对象保持 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); } } /** * 用作 K 的引用类型。 * @author <a href="http://www.agrael.cn">李翔</a> * */ public static enum ReferenceKeyType { /** 强引用 */ STRONG(Object.class), /** 软引用 */ SOFT(ReferenceMap.FinalizableKeySoftReference.class), /** 弱引用 */ WEAK(ReferenceMap.FinalizableKeyWeakReference.class), /** 虚引用 */ PHANTOM(ReferenceMap.FinalizableKeyPhantomReference.class); private final Class<?> referenceTypeClass; private ReferenceKeyType(Class<?> referenceTypeClass) { this.referenceTypeClass = referenceTypeClass; } Class<?> getReferenceTypeClass(){ return referenceTypeClass; } } /** * 用作 V 的引用类型。 * @author <a href="http://www.agrael.cn">李翔</a> * */ public static enum ReferenceValueType { /** 强引用 */ STRONG(Object.class), /** 软引用 */ SOFT(ReferenceMap.FinalizableValueSoftReference.class), /** 弱引用 */ WEAK(ReferenceMap.FinalizableValueWeakReference.class), /** 虚引用 */ PHANTOM(ReferenceMap.FinalizableValuePhantomReference.class); private final Class<?> referenceTypeClass; private ReferenceValueType(Class<?> referenceTypeClass) { this.referenceTypeClass = referenceTypeClass; } Class<?> getReferenceTypeClass(){ return referenceTypeClass; } } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(size()); out.writeFloat(loadFactor); out.writeInt(concurrencyLevel); for (Map.Entry<Object, Object> entry : 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(); this.initialCapacity = size; 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); } } } |
|
返回顶楼 | |
发表时间:2010-05-21
最后修改:2010-05-21
我已经发了一篇名叫《封装ConcurrentHashMap使其成为具有各种引用类型key与value的ReferenceMap》的帖子,那个是完整的介绍。
|
|
返回顶楼 | |
发表时间:2010-05-21
从来没用过。学习一下。多谢LZ
|
|
返回顶楼 | |
发表时间:2010-05-21
最后修改:2010-05-21
回Agrael:
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,呵呵呵。 |
|
返回顶楼 | |
发表时间:2010-05-21
Norther 写道 回Agrael:
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,还差一截。 呵呵,你所包名改改这个我觉得我没这样做,如果我改包名的话,也是cn.agrael.原包名。 这个ReferenceMap我修改过无数次,最终形成了现在的版本。 在这个版本之前,我发现了XWORK里也有类似的东西,而且比我写得更好,所以我就参考着修改了下,修改的仅仅是从之前的每次创建一个ReferenceMap都有一个线程清理变到无论创建多少个ReferenceMap都只有一个线程清理。 至于FinalizableReference命名这个,我想说的是,这个名字还不是我自己命的,是我国外一个朋友帮我命的,我英语不好,所以叫他帮忙取的。呵呵。 |
|
返回顶楼 | |
发表时间:2010-05-21
就之前我一直被WeakHashMap的并发问题困扰,在可能2年前吧,就准备封装ConcurrentHashMap来满足需求,但是当时到处找都没找到自己需要的,所以才自己写了个,经过很多次修改,最终才比较满意。后来发现XWORK里的时,已经和现在的代码区别不大了。至于为什么不实现ConcurrentMap。这个的话我觉得都到这一步了,如果哪天需要在ReferenceMap中单独出现这些方法的话,再改也没什么,毕竟现在我还有个CollectionUtils配合这个使用,呵呵。
|
|
返回顶楼 | |
发表时间:2010-05-21
Agrael 写道 Norther 写道 回Agrael:
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,还差一截。 呵呵,你所包名改改这个我觉得我没这样做,如果我改包名的话,也是cn.agrael.原包名。 这个ReferenceMap我修改过无数次,最终形成了现在的版本。 在这个版本之前,我发现了XWORK里也有类似的东西,而且比我写得更好,所以我就参考着修改了下,修改的仅仅是从之前的每次创建一个ReferenceMap都有一个线程清理变到无论创建多少个ReferenceMap都只有一个线程清理。 至于FinalizableReference命名这个,我想说的是,这个名字还不是我自己命的,是我国外一个朋友帮我命的,我英语不好,所以叫他帮忙取的。呵呵。 你国外的朋友不会是Bob Lee吧?强的! http://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/base/FinalizablePhantomReference.java |
|
返回顶楼 | |
发表时间:2010-05-21
Norther 写道 Agrael 写道 Norther 写道 回Agrael:
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,还差一截。 呵呵,你所包名改改这个我觉得我没这样做,如果我改包名的话,也是cn.agrael.原包名。 这个ReferenceMap我修改过无数次,最终形成了现在的版本。 在这个版本之前,我发现了XWORK里也有类似的东西,而且比我写得更好,所以我就参考着修改了下,修改的仅仅是从之前的每次创建一个ReferenceMap都有一个线程清理变到无论创建多少个ReferenceMap都只有一个线程清理。 至于FinalizableReference命名这个,我想说的是,这个名字还不是我自己命的,是我国外一个朋友帮我命的,我英语不好,所以叫他帮忙取的。呵呵。 你国外的朋友不会是Bob Lee吧?强的! http://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/base/FinalizablePhantomReference.java 绝对不是,而且当时我参考的也不是这个包的东西。 |
|
返回顶楼 | |
发表时间:2010-05-21
org.apache.commons.collections.map.ReferenceMap.java
此类在 commons-collections-3.2.1.jar 不知楼主有没有看过此类,并 和你自己所写有什么区别? |
|
返回顶楼 | |
发表时间:2010-05-21
JavaYwsEye 写道 org.apache.commons.collections.map.ReferenceMap.java
此类在 commons-collections-3.2.1.jar 不知楼主有没有看过此类,并 和你自己所写有什么区别? 我想你是问的我,不是楼主。 上面我就说了,不过我不知道你说的这个类,我看的是Xwork里的一个类,在我new一个实例就创建一个线程困扰的时候,看到那个类后把new一个实例就创建一个线程改为了只会有一个线程,除此之外,这个ReferenceMap已经和我发的代码差不多了。如果有相似的,我估计是思想大同小异吧。 |
|
返回顶楼 | |