Java缓存中弱引用应用

问题描述:
SEOURL 跳转地址的cache。利用map key(SeoCacheKey) value(url)的方式缓存,以每2小时策略和Entry<15000条策略,以及Memery<?策略更新缓存。由于key的设计过于粗狂,导致
key在缓存中占用太多内存,且key中的核心property生命周期过长,导致失真。
解决方案:
利用WeakReference弱引用,管理最初的核心property,使之成为一个真实的,不会导致memery膨胀的object。
代码如下,无需关注其他内容,最重要的是弱引用的实现和使用
public class SeoCacheKey {
	
	private static ReferenceQueue<RepositoryItem> PREFERENCEQUEUE =  new ReferenceQueue<RepositoryItem>();
	
    WeakReference<RepositoryItem> mRepositoryItemReference;
    
    Repository	mRepository;

    
    public SeoCacheKey(UrlTemplate pUrlTemplate, RepositoryItem pRepositoryItem, String pContextRoot) {
        this.mRepository = pRepositoryItem.getRepository();
		//弱引用管理此核心property对象
        this.mRepositoryItemReference = new WeakReference<RepositoryItem>(pRepositoryItem, PREFERENCEQUEUE);
    }
    
	//由于使用时存在多线程,同步此方法,确保换取后对象在生命周期内的唯一性
	public synchronized RepositoryItem getRepositoryItem(){
		
		RepositoryItem item = this.mRepositoryItemReference.get();
		if(item == null){
			if (StringUtil.empty(mItemID)) {
				throw (new IllegalArgumentException("The parameter \"mItemID\" can not be empty."));
			}
			if (StringUtil.empty(mItemDescriptorName)) {
				throw (new IllegalArgumentException("The parameter \"mItemDescriptorName\" can not be empty."));
			}
			try {
				item = mRepository.getItem(mItemID, mItemDescriptorName);
			} catch (RepositoryException e) {
				throw (new CustomRepositoryException("Can not get repository item whose id is " + mItemID + " and descriptor name is "
						+ mItemDescriptorName + ".", e));
			}
		}
		return item;
	}
}

关于java的强引用,软引用,弱引用,虚引用请google一把
如在工作中遇到需要做缓存的地儿,请不要忘记java中除了强引用(导致OutOfMemeryException)外,还有可爱的软引用,弱引用,以及可以监视对象被回收的虚引用。

对这个知识点的扩展之原子引用以确保原子性
public class SeoCacheKey {
	//原子引用
	AtomicReference<WeakReference<RepositoryItem>> mAtomicReference;
	
    WeakReference<RepositoryItem> mRepositoryItemReference;
    
    UrlTemplate urlTemplate;
    
    Repository	mRepository;
    
    String mRepositoryName;
    
    String mItemDescriptorName;
    
    String mItemID;

    String contextRoot;
    
    public SeoCacheKey(UrlTemplate pUrlTemplate, RepositoryItem pRepositoryItem, String pContextRoot) {
    	
    	this.urlTemplate = pUrlTemplate;
        this.mRepository = pRepositoryItem.getRepository();
        this.mRepositoryName = pRepositoryItem.getRepository().getRepositoryName();
        try {
			this.mItemDescriptorName = pRepositoryItem.getItemDescriptor().getItemDescriptorName();
		} catch (RepositoryException e) {
			throw new IllegalArgumentException("Get item descriptor name error!",e);
		}
        this.mItemID = pRepositoryItem.getRepositoryId();
        this.contextRoot = pContextRoot;
        WeakReference<RepositoryItem> repositoryItemReference = generateWeakReference(pRepositoryItem);
        this.mAtomicReference = new AtomicReference<WeakReference<RepositoryItem>>(repositoryItemReference);
    }
    
	public RepositoryItem getRepositoryItem() {
		RepositoryItem item = this.mAtomicReference.get().get();
		if (item != null) {
			return item;
		}
		if (StringUtil.empty(mItemID)) {
			throw (new IllegalArgumentException(
					"The parameter \"mItemID\" can not be empty."));
		}
		if (StringUtil.empty(mItemDescriptorName)) {
			throw (new IllegalArgumentException(
					"The parameter \"mItemDescriptorName\" can not be empty."));
		}
		try {
			item = mRepository.getItem(mItemID, mItemDescriptorName);
			WeakReference<RepositoryItem> repositoryItemReference = generateWeakReference(item);
			//确保了对象的原子性,使得其他线程在调用的这个类的时候,不会出现doublechecking的尴尬
			//关于doublechecking,请google。或参看http://spice.iteye.com/blog/1117370
			this.mAtomicReference.getAndSet(repositoryItemReference);
			return item;
		} catch (RepositoryException e) {
			throw (new CustomRepositoryException(
					"Can not get repository item whose id is " + mItemID
							+ " and descriptor name is " + mItemDescriptorName
							+ ".", e));
		}
	}

	private WeakReference<RepositoryItem> generateWeakReference(
			RepositoryItem item) {
		ReferenceQueue<RepositoryItem> referenceQueue = new ReferenceQueue<RepositoryItem>();
		WeakReference<RepositoryItem> repositoryItemReference = new WeakReference<RepositoryItem>(
				item, referenceQueue);
		return repositoryItemReference;
	}
}

猜你喜欢

转载自spice.iteye.com/blog/1112778