在使用java.util.concurrent类时,我应该同步以避免可见性问题吗?

时间:2010-10-28 06:49:33

标签: java multithreading concurrency java.util.concurrent java-memory-model

使用任何java.util.concurrent类时,是否仍需要在实例上同步访问以避免差异线程之间的可见性问题?

更详细地阐述问题

当使用java.util.concurrent的实例时,是否有可能一个线程修改实例(即,将一个元素放在一个并发的hashmap中),后续的线程将不会看到修改?

我的问题源于这样一个事实:如果对值的访问不同步,Java内存模型允许线程缓存值而不是直接从内存中获取值。

2 个答案:

答案 0 :(得分:3)

在java.util.concurrent包Memory Consistency Properties上,您可以检查包的Javadoc API:

  

所有课程的方法   java.util.concurrent及其   子包将这些保证扩展到   更高级别的同步。在   特别是:

     
      
  • 在将对象放入任何对象之前的线程中的操作   并发收集   在访问或删除之后发生之前的操作   来自集合的元素   另一个线程   [...]
  •   
  • “释放”同步器方法之前的操作,例如
      Lock.unlock,Semaphore.release和
      CountDownLatch.countDown
      在成功的“获取”方法之后发生之前的行动   比如Lock.lock,   Semaphore.acquire,Condition.await,   和CountDownLatch.await   另一个同步器对象   线程。
      [...]
  •   

因此,此包中的类确保了并发性,利用一组类进行线程控制(LockSemaphore等)。这些类以编程方式处理发生在之前的逻辑,即管理并发线程的FIFO堆栈,锁定和释放当前和后续线程(即使用Thread.wait()Thread.resume()等。

然后,(理论上)您不需要同步访问此类的语句,因为它们以编程方式控制并发线程访问。

答案 1 :(得分:0)

因为ConcurrentHashMap(例如)旨在从并发上下文中使用,所以您不需要进一步同步它。事实上,这样做可能会破坏它所引入的优化。

例如,Collections.synchronizedMap(...)表示一种使地图线程安全的方法,据我所知,它主要通过将所有调用包装在synchronized关键字中来实现。另一方面,像ConcurrentHashMap这样的东西会在集合中的元素之间创建同步的“桶”,从而实现更细粒度的并发控制,从而在大量使用时提供更少的锁争用。例如,它也可能无法锁定读取。如果你再次使用一些同步访问来包装它,你可能会破坏它。显然,你必须要小心所有对集合的访问都是syncrhronised等,这是新库的另一个优点;你不必担心(尽可能多!)。

java.lang.concurrent集合可以通过syncrhonised实现其线程安全性。在这种情况下,语言规范保证可见性。他们可以在不使用锁的情况下实现。我对此并不是很清楚,但我认为这里的可见性相同。

如果您在代码中看到丢失更新的内容,可能只是竞争条件。像ConcurrentHashpMap这样的东西会给你一个读取的最新值,而写入可能还没有被写入。这通常是在准确性和性能之间进行权衡。

重点是; java.util.concurrent东西是为了做这些事情所以我相信它确保可见性和使用volatile和/或加法同步化不应该。