最近在设计一个可缓存的类,发现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
相关推荐
这个问题的解决方案是使用JDK1.8中ConcurrentHashMap的另一个方法,即putIfAbsent方法。putIfAbsent方法可以在键不存在时,提供一个默认值作为回应。但是,putIfAbsent方法不具备computeIfAbsent方法的功能,它不能...
`ConcurrentHashMap`提供了多种线程安全的操作,如`putIfAbsent()`, `remove()`, `replace()`等,这些方法在并发环境下可以确保操作的原子性。同时,`ConcurrentHashMap`还支持弱一致性迭代器,这意味着在迭代过程中...
当线程需要获取锁时,程序会使用 ConcurrentHashMap 的 putIfAbsent 方法来检查锁是否已经存在,如果不存在,则创建一个新的锁对象,并将其存储在 ConcurrentHashMap 中。然后,程序会使用计数器来记录锁的状态,...
6. **原子性操作**:`ConcurrentHashMap`提供了诸如`putIfAbsent()`这样的原子操作,确保在插入元素时,如果键不存在,可以安全地插入,而不会因并发问题导致数据冲突。 在决定何时使用`ConcurrentHashMap`时,应...
添加元素时,`add`方法会调用`ConcurrentHashMap`的`putIfAbsent`,如果元素不存在则插入,否则不做任何处理,确保元素的唯一性。删除元素则使用`remove`方法,通过`key-value`键值对中的`value`为`null`来实现。...
此外,ConcurrentHashMap 还提供了其他高级特性,如支持原子操作的 putIfAbsent()、remove() 和 replace() 方法,这些方法能够在不使用额外同步的情况下保证操作的原子性。这些特性使得在并发编程中更易于保证数据的...
例如,查看ConcurrentHashMap的putIfAbsent()方法是如何实现线程安全的,或者研究CopyOnWriteArrayList是如何通过复制数组实现并发安全的。 在实际开发中,熟练运用这些并发集合能够帮助我们编写出更加高效、可靠的...
- **ConcurrentHashMap 的 putIfAbsent 方法**:这个方法可以原子地检查并插入键值对,如果键已经存在则不会插入新的值,这样可以减少不必要的锁操作。 - **使用 FutureTask 实现延迟加载**:通过将任务封装到 `...
Java 基础知识点总结 一、String 不可变性 * String 的不可变性来自于它的实现方式,String 的值被存储在一个字符数组中,并且该数组被声明为 final,无法被修改。 * 不可变性使得 String 可以被安全地共享和缓存...
`ConcurrentHashMap.putIfAbsent`和`CopyOnWriteArrayList`等容器利用了无锁机制,可以在高并发下保持高性能。 #### 六、关于锁使用的经验介绍 深入理解锁的使用,如公平锁与非公平锁、重入锁等概念,可以帮助...
在`concurrentMap`的实现中,HotCode可能涉及到并发操作的关键路径,如putIfAbsent、getOrCompute等。通过分析这些热点代码,我们可以找到性能瓶颈并进行针对性优化,比如使用更高效的并发数据结构或算法。 `Java ...
- **原子操作**:`ConcurrentHashMap` 提供了如 `putIfAbsent`、`remove` 和 `replace` 等原子操作方法,在保持线程安全的同时提供更高的性能。 #### 二、ThreadLocal 的作用与原理 **定义:** `ThreadLocal` 是 ...
this.singletonObjects.putIfAbsent(beanName, singletonObject); } catch (Exception ex) { // ... } } return singletonObject; } ``` 总的来说,Spring通过IoC和工厂模式实现了对bean的高效管理,通过单例...
无锁编程(Lock-free)是一种实现并发程序设计的技术,它避免使用传统的锁机制,而是通过原子操作(如java.util.concurrent.atomic包下的类)和无锁数据结构(如ConcurrentHashMap的putIfAbsent方法和...
- **一致性操作**:`ConcurrentHashMap`还提供了一些一致性操作方法,如`putIfAbsent`、`remove`、`replace`等,这些方法能够在保证数据一致性的同时,避免不必要的更新操作。 ##### 1.2 `BlockingQueue` `...
总结来说,Guava 提供了强大的缓存支持,特别是通过 `LoadingCache` 和 `CacheLoader` 的组合,能够轻松实现高效、线程安全的缓存功能。此外,Guava 还考虑到了异常处理等问题,使得开发者能够更加专注于业务逻辑的...
2. **`ConcurrentHashMap`的改进**:JDK7中的`ConcurrentHashMap`在并发性能上有了显著提升,提供了更细粒度的锁,减少了锁竞争。 五、其他特性 1. **钻石运算符**:在创建匿名内部类或泛型实例时,可以省略类型...
- **HashMap**:提供了 `containsKey`, `containsValue`, `putIfAbsent` 等方法。 - **HashTable**:提供了 `contains` 方法来判断是否存在某个值(已过时),而 `containsKey` 和 `containsValue` 是 `Map` 接口...
`ConcurrentHashMap`还提供了一系列一致性操作方法,如`putIfAbsent`、`remove`、`replace`等,这些方法可以在确保数据一致性的前提下高效地更新数据。 ##### 1.2 BlockingQueue `BlockingQueue`是一个线程安全的...