【坑】自己山寨缓存出现的坑自己踩
就在前两天,在编写一段业务逻辑的时候,考虑到数据库中的数据值是固定的,为了提高效率,自己做了一个Map的缓存,大致代码如下。
//缓存类 @service public class CacheService{ private Map<String,List<Object>> cache = new Concurrenthashmap<>(); public List<Object> get(String key){ return cache.get(key); } public void put(String key, List<Object> list){ cache.put(key,list); } public void del(String key){ cache.remove(key); } }
如上代码,乍看下来不会有什么问题,功能也可以正常实现。但是其实他是极其不安全的。
为什么怎么说?当我们其他的service把这个cache依赖注入的时候,如果要执行如下代码。执行之后会有什么问题?
List<Object> list = cacheService.get("A"); for(int i = list.size()-1 ; i >=0 ; i -- ){ if(needRemove){ list.remove(i); } }
执行完之后,当下次另外一个地方也需要去取cacheService中的“A”的时候,会发现LIST中元素的内容变少了,原因是,cacheService在放入和取出的时候都没有做copy,没有做copy导致的外部获取的list和内部cacheService中list的地址是同一个,外部修改的话,会同时修改掉内部的list的元素。这样的做法是极其不安全的。所以,只需要在get 和 put方法中添加collections.copy() 就不会出现如上的问题了。同样的问题还会出现在其他类似的集合中。
注:可以依赖一些代码规范检查的服务器或者插件,他们也可以帮你检查出类似的问题,比如获取数组的时候,需要clone等等