为什么Java的同步集合不使用读/写锁?

Miq*_*uel 17 java collections concurrency

在喜欢HashtableVector不喜欢的东西之后,当Collections同步包装器出现时,我认为同步将更有效地处理.现在我查看了代码,我很惊讶它只是用同步块包装集合.

ReadWriteLock例如,为什么不包含在集合中的SynchronizedMap?是否存在一些不值得的效率考虑因素?

Kon*_*che 12

读写锁是性能优化的一部分,这意味着它可以在某些情况下允许更大的并发性.必要条件是,它们应用于大多数时间读取但未修改的数据结构.

在其他条件下,它们的表现比独家锁更差,因为它们具有更大的复杂性,因此很自然.

如果读写锁的锁通常保持适度长时间并且对受保护资源仅进行少量修改,则效率最高.

因此,读写锁是否优于排它锁取决于用例.最终,您必须使用分析来衡量哪些锁具有更好的性能.

考虑到这一点,选择一个专用锁来Collections.synchronizedMap解决一般用例而不是大多数读者的特殊情况似乎是合适的.

更多链接

在此输入图像描述

[...]然而,在写操作更普遍的配置中,具有同步块的版本比基于使用Sun 1.6.0_07 JVM的读写锁定的版本快50%(与Sun 1.5相比快14%). 0_15 JVM).

在只有1个阅读器和1个写入器的低争用情况下,性能差异不那么极端,并且三种类型的锁中的每一种在至少一个机器/ VM配置上产生最快的版本(例如,注意ReentrantLocks是最快的带有Sun 1.5.0_15 JVM的2核机器.

  • @Miquel我同意,它并没有那么昂贵,因为我已经声明它只会表现稍差.但这只是我在理论上所知道的,虽然我在处理这些主题时遇到了一些有趣的基准,但我尝试在我的答案中添加一些来给出成本差异的具体数字. (2认同)
  • 非常感谢@platzhirsch,你添加的数据真让我感到惊讶.很高兴与知道如何支持他们的论点的人讨论! (2认同)
  • 但是我最担心的是,对于那些试图推出自己的锁定机制的人来说,这将成为一种诱惑.对于99%的问题空间,建议使用`synchronized`,因为您不必主动清除锁定.许多人正在进行过早优化或正在优化其应用程序的错误部分.但话虽如此,这是值得记住的. (2认同)

Gra*_*ray 7

我不认为使用ReadWriteLock(如果这就是你所说的)比使用synchronized关键字更快.这两种结构都强加了锁定并建立了内存障碍,并且"在之前发生"限制.

您可能正在谈论做一些聪明的事情Collections.synchronizedMap(...)和朋友,其中读取方法被读取锁定并且写入方法写入锁定以提高性能.这可能适用于java.util集合类,但Map如果get()计算方法或其他东西,可能会导致用户实现的同步问题- 即"只读"方法实际上对集合进行了更新.是的,这样做是个糟糕的主意.

ConcurrentHashmap被编写为高性能并volatile直接使用字段而不是synchronized块.这使得代码与之相比变得更加复杂,Collections.synchronizedMap(...)但也更快.这就是推荐用于高性能情况的原因Collections.synchronizedMap(new HashMap<...>()).


Joh*_*int 6

除了以下内容之外,大多数推理都已得到解决.SynchronizedMap/Set/List以及Hashtable和Vector依赖于同步的集合实例.因此,许多开发人员使用此同步来确保原子性.例如.

List syncList = Collections.synchronizedList(new ArrayList());

//put if absent
synchronized(syncList){
   if(!syncList.contains(someObject)){
     syncList.add(someObject);
   }
}
Run Code Online (Sandbox Code Playgroud)

这是所有操作的线程安全和原子,因为synchronizedList将自己同步(即添加,删除,获取).这就是为什么Hashtable类没有被改装以支持类似于ConcurrentHashMap的锁定条带化的主要原因.

因此,对于这些集合使用ReadWriteLock将失去原子操作的能力,除非您能够获取锁定实例.