Java 并发hashMap putIfAbsent方法功能
我是java世界的新手,探索并发哈希映射,在探索并发哈希映射API的同时,我发现了putifAbsent()方法Java 并发hashMap putIfAbsent方法功能,java,concurrenthashmap,Java,Concurrenthashmap,我是java世界的新手,探索并发哈希映射,在探索并发哈希映射API的同时,我发现了putifAbsent()方法 现在请告诉我们什么是it功能,我们什么时候实际需要它,如果可能,请用一个简单的小例子解释。aConcurrentHashMap的设计是为了让大量并发线程使用它 现在,如果您使用标准Map接口提供的方法,您可能会编写类似的代码 if(!map.containsKey("something")) { map.put("something", "a value"); }
现在请告诉我们什么是it功能,我们什么时候实际需要它,如果可能,请用一个简单的小例子解释。a
ConcurrentHashMap
的设计是为了让大量并发线程使用它
现在,如果您使用标准Map
接口提供的方法,您可能会编写类似的代码
if(!map.containsKey("something")) {
map.put("something", "a value");
}
这看起来不错,似乎可以完成任务,但它不是线程安全的。然后你会想,“啊,但是我知道synchronized
关键字”,然后把它改成这个
synchronized(map) {
if(!map.containsKey("something")) {
map.put("something", "a value");
}
}
这解决了问题
现在,您所做的是在检查密钥是否存在并将其添加到映射中时,锁定整个映射以进行读写操作
这是一个非常粗糙的解决方案。现在,您可以通过双重检查锁和重新锁定密钥等方式实现自己的解决方案,但这是一个非常复杂的代码,非常容易出现bug
因此,您可以使用JDK提供的解决方案
ConcurrentHashMap
是一个聪明的实现,它将Map
划分为多个区域并单独锁定,这样您就可以在没有外部锁定的情况下对映射进行并发、线程安全的读写
与实现中的所有其他方法一样,putIfAbsent
锁定密钥的区域,而不是整个Map
,因此允许同时在其他区域进行其他操作。AConcurrentHashMap
的设计使得大量并发线程可以使用它
现在,如果您使用标准Map
接口提供的方法,您可能会编写类似的代码
if(!map.containsKey("something")) {
map.put("something", "a value");
}
这看起来不错,似乎可以完成任务,但它不是线程安全的。然后你会想,“啊,但是我知道synchronized
关键字”,然后把它改成这个
synchronized(map) {
if(!map.containsKey("something")) {
map.put("something", "a value");
}
}
这解决了问题
现在,您所做的是在检查密钥是否存在并将其添加到映射中时,锁定整个映射以进行读写操作
这是一个非常粗糙的解决方案。现在,您可以通过双重检查锁和重新锁定密钥等方式实现自己的解决方案,但这是一个非常复杂的代码,非常容易出现bug
因此,您可以使用JDK提供的解决方案
ConcurrentHashMap
是一个聪明的实现,它将Map
划分为多个区域并单独锁定,这样您就可以在没有外部锁定的情况下对映射进行并发、线程安全的读写
与实现中的所有其他方法一样,putIfAbsent
锁定密钥的区域,而不是整个Map
,因此允许同时在其他区域进行其他操作。当多个线程可以同时访问同一映射时,使用ConcurrentHashMap。在这种情况下,手动实现putIfAbsent()是不可接受的,如下所示:
if (!map.containsKey(key)) {
map.put(key, value);
}
实际上,两个线程可能并行执行上面的块并进入竞争条件,其中两个线程都首先测试是否缺少密钥,然后都将自己的值放入映射中,从而打破程序的不变量
因此,ConcurrentHashMap提供了putIfAbsent()
操作,确保以原子方式完成此操作,从而避免竞争条件。当多个线程可以同时访问同一映射时,将使用ConcurrentHashMap。在这种情况下,手动实现putIfAbsent()是不可接受的,如下所示:
if (!map.containsKey(key)) {
map.put(key, value);
}
实际上,两个线程可能并行执行上面的块并进入竞争条件,其中两个线程都首先测试是否缺少密钥,然后都将自己的值放入映射中,从而打破程序的不变量
ConcurrentHashMap因此提供了putIfAbsent()
操作,确保以原子的方式完成此操作,从而避免竞争条件。想象一下,我们需要一个惰性初始化的命名单例bean缓存。下面是一个基于ConcurrentHashMap的无锁实现:
ConcurrentMap<String, Object> map = new ConcurrentHashMap<>();
<T> T getBean(String name, Class<T> cls) throws Exception {
T b1 = (T) map.get(name);
if (b1 != null) {
return b1;
}
b1 = cls.newInstance();
T b2 = (T) map.putIfAbsent(name, b1);
if (b2 != null) {
return b2;
}
return b1;
}
ConcurrentMap=new ConcurrentHashMap();
T getBean(字符串名,类cls)引发异常{
tb1=(T)map.get(name);
如果(b1!=null){
返回b1;
}
b1=cls.newInstance();
t2=(T)map.putIfAbsent(名称,b1);
如果(b2!=null){
返回b2;
}
返回b1;
}
请注意,它解决了与双重检查锁定相同的问题,但没有锁定。想象一下,我们需要一个惰性初始化命名单例bean的缓存。下面是一个基于ConcurrentHashMap的无锁实现:
ConcurrentMap<String, Object> map = new ConcurrentHashMap<>();
<T> T getBean(String name, Class<T> cls) throws Exception {
T b1 = (T) map.get(name);
if (b1 != null) {
return b1;
}
b1 = cls.newInstance();
T b2 = (T) map.putIfAbsent(name, b1);
if (b2 != null) {
return b2;
}
return b1;
}
ConcurrentMap=new ConcurrentHashMap();
T getBean(字符串名,类cls)引发异常{
tb1=(T)map.get(name);
如果(b1!=null){
返回b1;
}
b1=cls.newInstance();
t2=(T)map.putIfAbsent(名称,b1);
如果(b2!=null){
返回b2;
}
返回b1;
}
请注意,它解决了与双重检查锁定相同的问题,但没有锁定。看看(i)
的分段以及方法put(paramK,i,paramV,true)
的工作原理。我想true
是值得一看的。看看segmentFor(I)
以及方法如何放置(paramK,I,paramV,true)
。我想这是值得一看的。