【发布时间】:2014-02-17 09:59:04
【问题描述】:
我有一个共享资源——一个简单的 POJO 包装了一个 HashMap——它将在启动时初始化一次,然后只能被许多线程读取,可能同时读取(上下文是一个 Web 应用程序)。我需要同步对对象的访问(或者使用并发哈希)还是安全地进行多个同时读取?同步会增加大量开销吗?
【问题讨论】:
标签: java thread-safety readonly
我有一个共享资源——一个简单的 POJO 包装了一个 HashMap——它将在启动时初始化一次,然后只能被许多线程读取,可能同时读取(上下文是一个 Web 应用程序)。我需要同步对对象的访问(或者使用并发哈希)还是安全地进行多个同时读取?同步会增加大量开销吗?
【问题讨论】:
标签: java thread-safety readonly
如果您确保所有写入发生在所有读取之前,您可以跳过对该映射的读取访问同步。其含义在JLS 7 chapter 17.4.5 中有描述。
实际上,您必须确保在任何其他将访问它的线程启动之前填充HashMap,并且在此之后不会修改其内容。
此解决方案有效的原因是Thread.start() 调用强制同步,因此保证在该调用之前所做的所有更改在该调用之后对新旧线程都是可见的。如果您在调用之后修改对象,则此保证将丢失,并且需要同步访问。
【讨论】:
otherThread.start() 的调用保证该调用之前的任何修改对otherThread 可见的事实。如果您以某种不同步的方式将映射的引用传递给已经运行的线程,您将失去保证(AFAIK pastebin.com/p3mpbNxv 应该有这个问题。)以正确的顺序执行的代码并不能保证它实际上是按该顺序发生的除非你做一些事情来保证这种发生前的关系。
如果您确定只需要执行读取操作,则不需要同步。这也是同样的原因有不同的锁——在ReadWriteLock中读写。
ReadWriteLock 维护一对关联的锁,一个用于只读操作,一个用于写入。只要没有写者,读锁可能被多个读线程同时持有。写锁是独占的。
由于您没有编写器,因此无需同步。
【讨论】:
由于多次读取的结果不依赖于事件的顺序,我会说你没有遇到竞争条件 (http://en.wikipedia.org/wiki/Race_condition),因此没有必要同步访问。
【讨论】: