Java缓存中弱引用应用

[b]问题描述:[/b]
SEOURL 跳转地址的cache。利用map key(SeoCacheKey) value(url)的方式缓存,以每2小时策略和Entry<15000条策略,以及Memery<?策略更新缓存。由于key的设计过于粗狂,导致
key在缓存中占用太多内存,且key中的核心property生命周期过长,导致失真。
[b]解决方案:[/b]
利用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;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值