`
Agrael
  • 浏览: 14992 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

封装ConcurrentHashMap成为具有各种引用类型key与value的ConcurrentReferenceMap,完美取代WeakHashMap

阅读更多

        在非并发访问时,常用的为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接口。

分享到:
评论
15 楼 Agrael 2010-05-31  
logic 写道
Agrael 写道
logic 写道
你好,谢谢你的回答,明白了,不过,我还想在请教一个问题。
使用Reference类实际是想让一个实例对象(Object)进行资源内存回收,但是,自己本身也创建了
WeakReference实例对象(比如new WeakReference(...)),这个WeakReference实例对象同样占用内存,
有此可推出,通过一个新建WeakReference象(内存创建)来回收一个实例对象(Object内存回收),这符合常理吗?还望赐教。

JVM对Reference是特殊处理的。

能否再具体点?谢谢

这个还不是太好举,这样吧,你看看Reference这个类中有一行。

private T referent;		/* Treated specially by GC */


这个本来是强引用属于,但是旁边的注释说明,虚拟机会特殊对待这个引用。所以在Reference这个实例的引用还在的时候,里面的这个private T referent;才可以被回收。
当然这个只是一方面。
14 楼 logic 2010-05-31  
Agrael 写道
logic 写道
你好,谢谢你的回答,明白了,不过,我还想在请教一个问题。
使用Reference类实际是想让一个实例对象(Object)进行资源内存回收,但是,自己本身也创建了
WeakReference实例对象(比如new WeakReference(...)),这个WeakReference实例对象同样占用内存,
有此可推出,通过一个新建WeakReference象(内存创建)来回收一个实例对象(Object内存回收),这符合常理吗?还望赐教。

JVM对Reference是特殊处理的。

能否再具体点?谢谢
13 楼 Agrael 2010-05-31  
logic 写道
你好,谢谢你的回答,明白了,不过,我还想在请教一个问题。
使用Reference类实际是想让一个实例对象(Object)进行资源内存回收,但是,自己本身也创建了
WeakReference实例对象(比如new WeakReference(...)),这个WeakReference实例对象同样占用内存,
有此可推出,通过一个新建WeakReference象(内存创建)来回收一个实例对象(Object内存回收),这符合常理吗?还望赐教。

JVM对Reference是特殊处理的。
12 楼 logic 2010-05-31  
你好,谢谢你的回答,明白了,不过,我还想在请教一个问题。
使用Reference类实际是想让一个实例对象(Object)进行资源内存回收,但是,自己本身也创建了
WeakReference实例对象(比如new WeakReference(...)),这个WeakReference实例对象同样占用内存,
有此可推出,通过一个新建WeakReference象(内存创建)来回收一个实例对象(Object内存回收),这符合常理吗?还望赐教。
11 楼 Agrael 2010-05-29  
logic 写道
请教一个问题,如果PhantomReference引用的时候,gc回收执行后,再执行remove()方法,结果一直阻塞到那里,好像没有对象引用返回,这是什么回事?

代码如下:
//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中的对象被回收,所以回一直阻塞。
10 楼 logic 2010-05-26  
请教一个问题,如果PhantomReference引用的时候,gc回收执行后,再执行remove()方法,结果一直阻塞到那里,好像没有对象引用返回,这是什么回事?

代码如下:
//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的代码中,是否也可能会产生一直阻塞的现象?
9 楼 Agrael 2010-05-26  
mercyblitz 写道
Agrael 写道
mercyblitz 写道
Agrael 写道
mercyblitz 写道
首先楼主这种精神值得表扬。
如果我没有理解错的话,你的思路就是,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的问题。
8 楼 mercyblitz 2010-05-24  
Agrael 写道
mercyblitz 写道
Agrael 写道
mercyblitz 写道
首先楼主这种精神值得表扬。
如果我没有理解错的话,你的思路就是,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的本地方法,但是也是一种很好的设计。

题外话,我很欣赏楼主,呵呵,因为我也这样的人,喜欢重复发明轮子,为什么不能?



呵呵,其实我还比较喜欢发明轮子的。其实看看现在的开源框架,是否一个又一个轮子呢?


勇于创造,才有创新,凭空不能想象出伟大。
7 楼 Agrael 2010-05-24  
mercyblitz 写道
Agrael 写道
mercyblitz 写道
首先楼主这种精神值得表扬。
如果我没有理解错的话,你的思路就是,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的本地方法,但是也是一种很好的设计。

题外话,我很欣赏楼主,呵呵,因为我也这样的人,喜欢重复发明轮子,为什么不能?



呵呵,其实我还比较喜欢发明轮子的。其实看看现在的开源框架,是否一个又一个轮子呢?
6 楼 mercyblitz 2010-05-21  
Agrael 写道
mercyblitz 写道
首先楼主这种精神值得表扬。
如果我没有理解错的话,你的思路就是,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的本地方法,但是也是一种很好的设计。

题外话,我很欣赏楼主,呵呵,因为我也这样的人,喜欢重复发明轮子,为什么不能?
5 楼 Agrael 2010-05-21  
mercyblitz 写道
首先楼主这种精神值得表扬。
如果我没有理解错的话,你的思路就是,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、谢谢这个,非常好的提议:)
4 楼 mercyblitz 2010-05-21  
首先楼主这种精神值得表扬。
如果我没有理解错的话,你的思路就是,Daemon线程在不停“GC”(你这里的finalizeReferent)非强引用,不过JVM启动的时候,有一个Finalizer的线程在执行。

这里有几个问题:
1.三种非强引用的生命周期不同,软引用是在内存不足的情况被清理,弱引用是在对象不在关联,幻想的话,是已经被GC掉了。
2.ReferenceMap实现中,保存全部的是强引用对象,程序中并不能确定合适清理。
3.因为第2点,会产生内存泄漏。
4.命名,加一个Concurrent吧。


3 楼 Agrael 2010-05-21  
无论创建多少个ReferenceMap的实例都只有一个守护线程并不觉得heavy-weight。
value的引用会有这样的场景。例如Class
2 楼 beneo 2010-05-21  
用一个线程去做清理工作是不是太 heavy-weight 了

此外我不明白什么叫做 value 也需要引用?我好奇有这种场景应用么?
1 楼 Agrael 2010-05-21  
<p>这篇文章也是回复2个帖子的问题。<br>第一个是在今年2月的帖子《<a href="/topic/587995?page=2#1368579" target="_blank">WeakHashMap的神话</a>》</p>
<p>第二个是在《<a href="/topic/670414" target="_blank">Google
Collections中强大的Concurrent MapMaker</a>》</p>
<p> </p>

相关推荐

    简单的key value hashmap

    哈希映射(HashMap)是Java编程语言中一个非常重要的数据结构,它在《简单的key value hashmap》中被提及,通常用于存储键值对(key-value pairs)。HashMap是Java集合框架的一部分,它提供了高效的查找、插入和删除...

    java源码剖析-ConcurrentHashMap

    与传统的`Hashtable`相比,`ConcurrentHashMap`具有更高的并发性能,这主要得益于它的分段锁技术和非阻塞算法。 #### 二、`ConcurrentHashMap`的基本概念 1. **分段锁技术**:`ConcurrentHashMap`内部采用了分段锁...

    高薪程序员面试题精讲系列49之说说ConcurrentHashMap#put方法的源码及数。。。.pdf,这是一份不错的文件

    ConcurrentHashMap#put方法源码解析 ConcurrentHashMap是Java并发编程中的一个重要组件,用于解决高并发情况下的数据存储问题。在面试中,ConcurrentHashMap的底层原理、put方法的实现细节都是高频考点。本文将对...

    ConcurrentHashMap源码剖析

    其中,`key`和`hash`字段用于存储键和计算后的哈希值,`value`字段用于存储值,而`next`字段则用于连接同一个`Segment`中的多个`HashEntry`形成链表。 **3. 扩容机制** 当一个`Segment`中的元素数量达到一定阈值时...

    ConcurrentHashMap的实现原理

    Node 是 ConcurrentHashMap 中的一个基本组件,保存 key,value 及 key 的 hash 值的数据结构,其中 value 和 next 都用 volatile 修饰,保证并发的可见性。 JDK8 中 ConcurrentHashMap 的结构由于引入了红黑树,...

    HashMap&ConcurrentHashMap.key

    HashMap& ConcurrentHashMap 深度解析

    java本地缓存ConcurrentHashMap

    java本地缓存ConcurrentHashMap

    JDK1.8中ConcurrentHashMap中computeIfAbsent死循环bug.docx

    在JDK 1.8版本中,`ConcurrentHashMap`中的`computeIfAbsent`方法存在一个潜在的死循环问题。这个bug主要出现在并发操作时,当`ConcurrentHashMap`需要进行扩容并且`computeIfAbsent`正在执行计算的过程中,可能会...

    Java中遍历ConcurrentHashMap的四种方式详解

    Java中遍历ConcurrentHashMap的四种方式详解 Java中遍历ConcurrentHashMap的四种方式详解是Java开发中一个非常重要的知识点。ConcurrentHashMap是Java中一种高效且线程安全的HashMap实现,它提供了高效的读写操作...

    程序员面试加薪必备:ConcurrentHashMap底层原理与源码分析深入详解

    程序员面试加薪必备_ConcurrentHashMap底层原理与源码分析深入详解

    HashMap与ConcurrentHashMap面试要点.pdf

    ### HashMap和ConcurrentHashMap面试要点详解 #### HashMap面试要点 ##### HashMap底层数据结构 **JDK7与JDK8的差异:** - **JDK7的HashMap**底层是由数组+链表构成的。在JDK7中,链表采用头插法(head-...

    ConcurrentHashMap源码解析

    与传统的HashMap相比,ConcurrentHashMap在多线程环境下具有更好的性能,尤其是在读多写少的场景下。它通过引入锁分段技术解决了并发环境下效率低下的问题。 首先,我们来了解什么是线程安全的HashMap。HashMap在单...

    concurrenthashmap1.7.docx

    如果链表中存在与`key`相同的节点,那么更新节点的`value`,否则创建新的`HashEntry`对象并插入链表头部。 `put`方法中的`scanAndLockForPut`方法用于处理获取锁的逻辑。它采用循环尝试获取锁,同时检查链表是否有...

    java7-8中的 HashMap和ConcurrentHashMap全解析.pdf

    在Java 7中,HashMap的内部结构主要由一个Entry数组组成,每个Entry包含key、value、hash值和指向下一个Entry的引用。HashMap的put过程主要包括以下几个步骤: 1. 计算key的哈希值hash。 2. 根据数组长度和哈希值...

    Map是一种键值对(key-value)数据结构

    Map,也常被称为哈希表或字典,是数据结构中的一种重要类型,它允许我们通过键(key)来快速查找、添加和删除对应的值(value)。在各种编程语言中,如Java、C++、Python等,都有内置的Map实现。 Map的基本工作原理...

    Java利用ConcurrentHashMap实现本地缓存demo

    Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~

    Java并发编程笔记之ConcurrentHashMap原理探究.docx

    Java并发编程中的ConcurrentHashMap是HashMap的一个线程安全版本,设计目标是在高并发场景下提供高效的数据访问。相比HashTable,ConcurrentHashMap通过采用锁分离技术和更细粒度的锁定策略来提升性能。HashTable...

Global site tag (gtag.js) - Google Analytics