java ehcache例子_Java Cache 的HashMap实现, 适用场景及分布式ehcache实例

cache是老生常谈的事情,这里我想强调一下KISS原则,就是keep it simple and stupid。最近看到很多场景下cache使用的不适当,特别是被过度使用了。一个简单键值存储并不需要复杂的cache方案,好的方案就是用最简单的方法解决问题。简洁是美!

一个标准Cache的主要特征是:

过期时间

容量规划(重要)

清除策略(重要)

命中率统计

基于以上特征,使用HashMap作为本地cache似乎很不适当。更重要的是,有不少朋友认为HashMap可能会使内存耗尽。其实不然,自jdk1.2后,Java就引入了WeakHashMap。看看api文档是怎么说的:对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除,因此,该类的行为与其他的 Map 实现有所不同。

这个翻译明显有点烂,总结一下,和强引用的HashMap相比,WeakHashMap在本身引用不被回收的前提下允许GC回收它的键值对。当GC发现内存即将耗尽且没有其他对象可以释放时,会主动回收WeakHashMap所占用的对象。因此使用WeakHashMap作为本地cache是不会造成内存耗尽。如果你仅仅需要一个简单的键值对存储,而并不关心命中率统计,那么放心的使用WeakHashMap作为cache吧。

通过简单的包装,就可以为你的HashMap增加过期时间和容量规划。而且比其他cache更高效。openfire的DefaultCache就是一个很好的例子:http://svn.igniterealtime.org/svn/repos/openfire/trunk/src/java/org/jivesoftware/util/cache/DefaultCache.java

DefaultCache的核心是HashMap,另外增加了一层很薄的包装来实现过期和LRU。DefaultCache包括两个LinkedList,一个用于存储插入顺序,另一个用于存储插入时间。当添加cache时,都addFirst。当cache size达到临界值时,从最尾部删除。有朋友测试过,比ehcache快5倍。

如果本地cache不能满足你的要求,ehcache是个很好的选择。不仅仅作为分布式的cache,甚至作为状态同步,ehcache都有非常优秀的案例。也可以实现多机copy。分享一个数据,某生产系统中ehcache每天处理17,466,415次replication。

基于ehcache的分布式缓存,你可以简单的实现分布式计算。分析一个场景,某iOS后端服务要求用户先注册ios设备,可以按下图处理设备信息。DeviceServer接受device注册后同步copy的本地cache和ehcache。该ehcache按以下方式配置成对。本地cache再定期(每隔几秒钟)从ehcache中加载peer server注册的数据。

72522092_1.jpg

ehcache.xml 写道

class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"

properties="peerDiscovery=manual,

rmiUrls=//192.168.0.1:20121/testCache"/>

class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"

properties="hostName=192.168.0.2,port=20121,socketTimeoutMillis=60000"/>

maxElementsInMemory="20000"

eternal="false"

overflowToDisk="false"

memoryStoreEvictionPolicy="LRU">

properties="replicateAsynchronously=true,

replicatePuts=true,

replicateUpdates=true,

replicateUpdatesViaCopy=true,

asynchronousReplicationIntervalMillis=2000"

/>

peer server的hostName和rmiUrls配置需要做相应改动。

伪代码如下

Java style fake code代码 72522092_2.pnginit() {

cacheManager = new net.sf.ehcache.CacheManager(ThisClass.class.getResource("/ehcache.xml"));

testCache = cacheManager.getCache("testCache");

}

sync() {

while(true) {

List keys = testCache.getKeysNoDuplicateCheck();

for (int i = 0; i 

net.sf.ehcache.Element element = testCache.get(keys.get(i));

MyObj changed = (MyObj) element.getValue();

// do magic

testCache.remove(keys.get(i), true);

}

}

}

根据KISS原则,建议简单状态同步都使用ehcache完成。知识投入低,且易于维护。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值