最近在设计一个可缓存的类,发现putIfAbsent使用还是有些坑要注意的,总结一下。之前的代码如下
private static ConcurrentHashMap<String, Pattern> compliedPattern = new ConcurrentHashMap<String, Pattern>(); public static Pattern getPattern(String pattern) { return compliedPattern.putIfAbsent(pattern, Pattern.compile(pattern)); }
之前以为这样一行代码就完美了,结果测试每次都返回null,查看api看到文档:
写道
public V putIfAbsent(K key,
V value)
如果指定键已经不再与某个值相关联,则将它与给定值关联。这等价于:
if (!map.containsKey(key))
return map.put(key, value);
else
return map.get(key);
除了原子地执行此操作之外。
指定者:
接口 ConcurrentMap<K,V> 中的 putIfAbsent
参数:
key - 与指定值相关联的键
value - 与指定键相关联的值
返回:
以前与指定键相关联的值,如果该键没有映射关系,则返回 null
抛出:
NullPointerException - 如果指定键或值为 null
V value)
如果指定键已经不再与某个值相关联,则将它与给定值关联。这等价于:
if (!map.containsKey(key))
return map.put(key, value);
else
return map.get(key);
除了原子地执行此操作之外。
指定者:
接口 ConcurrentMap<K,V> 中的 putIfAbsent
参数:
key - 与指定值相关联的键
value - 与指定键相关联的值
返回:
以前与指定键相关联的值,如果该键没有映射关系,则返回 null
抛出:
NullPointerException - 如果指定键或值为 null
这个意思是如果key不存在必然返回null,因为put方法返回的value是之前有映射的value。那么改成这样如何?
public static Pattern getPattern(String pattern) { Pattern p = Pattern.compile(pattern); Pattern ret = compliedPattern.putIfAbsent(pattern, p); if (ret == null) { return ret; } else { return p; } }
但这样还搞个毛的缓存啊,每次都会compile了。正确的解法是:
public static Pattern getPattern(String pattern) { Pattern ret = compliedPattern.get(pattern); if (ret == null) { Pattern newPattern = Pattern.compile(pattern); ret = compliedPattern.putIfAbsent(pattern, Pattern.compile(pattern)); if (ret == null) { ret = newPattern; } } return ret; }
参考:
http://stackoverflow.com/questions/3752194/best-practice-to-use-concurrentmaps-putifabsent
http://stackoverflow.com/questions/10743622/concurrenthashmap-avoid-extra-object-creation-with-putifabsent
http://en.wikipedia.org/wiki/Double-checked_locking
相关推荐
java源码剖析-ConcurrentHashMap
Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~
ConcurrentHashMap源码剖析
源码分析见我博文:http://blog.csdn.net/wabiaozia/article/details/50684556
ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的...
ConcurrentHashMap具体是怎么实现线程安全的呢,肯定不可能是每个方法加synchronized,那样就变成了HashTable。
这时候ConcurrentHashMap达到容量扩容而忽略了ReservationNode情况,调用put的时候在synchronized(f)没有对ReservationNode处理,所以会出现死循环。 在jdk1.8和1.9中对比 http://gee.cs.oswego.edu/cgi- bin/...
解析concurrenthashmap的源码,学习多线程的思想
ConcurrentHashMap是J.U.C(java.util.concurrent包)的重要成员,它是HashMap的一个线程安全的、支持高效并发的版本。在默认理想状态下,ConcurrentHashMap可以支持16个线程执行并发写操作及任意数量线程的读操作。...
程序员面试加薪必备_ConcurrentHashMap底层原理与源码分析深入详解
java本地缓存ConcurrentHashMap
Java——并发容器之ConcurrentHashMap;Java——并发容器之ConcurrentHashMap;Java——并发容器之ConcurrentHashMap;Java——并发容器之ConcurrentHashMap;Java——并发容器之ConcurrentHashMap;Java——并发...
java7-8中的 HashMap和ConcurrentHashMap全解析
ConcurrentHashMap是一个线程安全的HashTable,它的主要功能是提供了一组和HashTable功能相同但是线程安全的方法。ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的...
ConcurrentHashMap之实现细节
ConcurrentHashMap的实现原理(JDK1.7和JDK1.8),并说明了在jdk1.7与jdk1.8的不同实现原理
concurrenthashmap1.7的源码分析
Java并发编程之ConcurrentHashMap Java并发编程之ConcurrentHashMap.pdf
ConcurrentHashMap的实现原理(纯干货)
java7-8中的 HashMap和ConcurrentHashMap全解析 如果你想了解底层的逻辑就来看看吧