HashMap作为缓存时的性能优化及与redis,EhCache等的应用比较

来源:互联网 发布:美柚 app 数据库设计 编辑:程序博客网 时间:2024/06/01 07:32

系统中在用hashmap作为缓存,所以不得不考虑一些因素:多线程并发,最大容量,性能,以及与redis,EhCache等的优劣比较

1、容量的问题:

源码中,HashMap的最大容量为1<<30。HashMap的初始默认容量是16,默认负载因子0.75,也就是说,随着数据的不断插入,当数据量不断增大,超过现有容量*负载因子的时候,就是进行容量扩充,即resize操作,而这个操作需要将原来数组的数据逐个全部重新放入到新生成的大容量的数组里面去,这样的代价就会比较高,尤其是hashmap容量在不断迅速增长的情况下。因此,类似我们现在这个系统中,hashmap中需要缓存的数据量基本上是比较稳定的(在可预见的未来不会出现暴增的情况,因此只要在一定范围内,也不会造成内存的急剧膨胀),这种情况下可以考虑在生成hashmap的时候就直接指定一个容量以及负载因子;而且在我们的系统中,hashmap缓存的其实就是一张数据表的数据,这样这个指定的容量其实就可以根据数据表现在的长度来获得。

2、多线程并发的问题

HashMap本身不是线程安全的,因此不能用于多线程并发,因为多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100%,但是java中提供了一个ConcurrentHashMap,这个map是线程安全的,通过对get操作不加锁,对put操作分块加锁的方式来保证线程安全的同时还能有较高的读写性能,详细的介绍可以参考:http://goldendoc.iteye.com/blog/1103980,http://www.infoq.com/cn/articles/ConcurrentHashMap

3、操作性能没有进行测试,稍后再来测试这个,暂时可以参考http://blog.csdn.net/java2000_net/article/details/3373181,http://blog.csdn.net/liuzhengkang/article/details/2916829,但是后者看评论好像是有争议的。


在我们的系统中,需要缓存的内容就是一些设备的实时信息,因此总的数量并不会太大,而且不会有数量上的急剧变动,因此用java原生的concurrenthashmap在容量上应该是没有问题的,多线程操作也没有问题;用redis的话还需要建立到redis的连接,然后提交查询请求,等待返回结果,这样会耗费相当多的时间;还有一点,因为实时信息并不需要考虑淘汰旧数据的问题,也就用不到Ehcache及redis等的LRU算法等内容,因此结合本项目实际可以直接采用原生的map而不用专门的缓存服务,当然,如果其他系统中数据量非常大或者存在其他因素的情况下,就得根据实际情况来选择实现方案了。