ConcurrentHashMap和复合操作

Hashtable和Collections.synchronizedMap是线程安全的,但仍然是复合操作

if (!map_obj.containsKey(key)) { map_obj.put(key, value); } 

需要外部同步:

 synchronized(map_obj) { if (!map_obj.containsKey(key)) { map_obj.put(key, value); } } 

假设我们有ConcurrentHashMap(CHM)而不是Hashtable或HashMap。 CHM为上述复合操作提供了另一种putIfAbsent()方法,因此无需外部同步。

但是假设CHM没有提供putIfAbsent() 。 然后我们可以写下面的代码:

 synchronized(concurrenthashmap_obj) { if (!concurrenthashmap_obj.containsKey(key)) { concurrenthashmap_obj.put(key, value); } } 

我的意思是我们可以在CHM对象上使用外部同步吗?它会起作用吗?

对于上面的复合操作,在CHM中有putIfAbsent()方法,但是如果我们使用CHM,如何为其他复合操作实现线程安全性。 我的意思是我们可以在CHM对象上使用外部同步吗?

不,您不能使用外部同步来确保复合操作在ConcurrentHashMapprimefaces性。

确切地说,您可以使用外部同步来确保复合操作的primefaces性,但是只有当ConcurrentHashMap所有操作ConcurrentHashMap在同一个锁上同步时(尽管在这种情况下使用ConcurrentHashMap没有意义 – 您可以用常规HashMap )。

具有外部同步的方法仅适用于HashtableCollections.synchronizedMap()因为它们保证它们的基本操作也在这些对象上synchronized 。 由于ConcurrentHashMap不提供这样的保证,原始操作可能会干扰复合操作的执行,从而破坏其primefaces性。

但是, ConcurrentHashMap提供了许多方法,可用于以乐观的方式实现复合操作:

  • putIfAbsent(key, value)
  • remove(key, value)
  • replace(key, value)
  • replace(key, oldValue, newValue)

您可以使用这些操作来实现某些复合操作,而无需进行明确的同步,就像对AtomicReference ,等等。

没有任何理由你不能。 传统同步适用于所有内容,没有针对它们的特殊例外。 ConcurrentHashMaps只是使用更优化的线程安全机制,如果你想做更复杂的事情,回退到传统的同步可能实际上是你唯一的选择(那和使用锁)。

您始终可以使用synchronized块。 java.util.concurrent的花哨集合并没有禁止它,它们只是使它在大多数常见用例中都是多余的。 如果您正在执行复合操作(例如 – 您要插入两个必须始终具有相同值的键),则不仅可以使用外部同步 – 您必须这样做

例如:

 String key1 = getKeyFromSomewhere(); String key2 = getKeyFromSomewhereElse(); String value = getValue(); // We want to put two pairs in the map - [key1, value] and [key2, value] // and be sure that in any point in time both key1 and key2 have the same // value synchronized(concurrenthashmap_obj) { concurrenthashmap_obj.put(key1, value); // without external syncronoziation, key1's value may have already been // overwritten from a different thread! concurrenthashmap_obj.put(key2, value); } 

由于ConcurrentHashMap实现了Map接口,它确实支持每个基本Map都具有的所有function。 所以是的:你可以像任何其他地图一样使用它并忽略所有额外的function。 但是那时你基本上会有一个较慢的HashMap。

同步Map和并发Map之间的主要区别在于 – 正如名称所示 – 并发。 想象一下,你有100个想要从Map中读取的线程,如果你synchronize你就可以阻止99个线程,1个可以完成工作。 如果使用并发,则100个线程可以同时工作。

现在,如果你考虑使用线程的实际原因,你很快就会得出结论,你应该摆脱每一个可能的synchronized块。

这完全取决于“其他复合操作”和“工作”的含义。 同步与ConcurrentHashMap的工作方式与其他任何对象的工作方式完全相同。

因此,如果您希望将某些复杂的共享状态更改视为primefaces更改,则必须在同一锁上同步对此共享状态的所有访问。 这个锁可以是Map本身,也可以是另一个对象。

关于java.util.concurrent.ConcurrentHashMap

  • “在依赖于线程安全但不依赖于其同步细节的程序中,Hashtable可与Hashtable完全互操作:它们不会抛出ConcurrentModificationException。”

  • “允许更新操作之间的并发”

关于java内存

一般而言,从同步角度来看,读取是安全的,但不是内存的立场。

另请参见“ http://www.ibm.com/developerworks/java/library/j-jtp03304/ ”。

因此,应使用synchronizatonvolatile来管理并发读取(与写入相比)。

关于putIfAbsent

putIfAbsent是你的朋友 :

如果指定的键尚未与值关联,请将其与给定键关联

 value. This is equivalent to if (!map.containsKey(key)) return map.put(key, value); else return map.get(key); 

除了动作执行!!!primefaces!!!