使用ConcurrentHashMap消除了数据可见性问题?

时间:2010-12-29 18:10:30

标签: java concurrency concurrenthashmap

我已阅读Java Concurrency in Practice并留下了这个问题:当我使用ConcurrentHashMap时,我还需要担心本书第一部分中讨论的数据并发问题?以下是我的一个程序中的几个例子:

1。交易者的当前位置(共享整数,其中'整数'是数学术语)

此数字表示trader对象当前拥有的内容并定义其状态。它必须阅读它的位置以了解该做什么(寻找开始一个新的位置,或管理当前的位置)。 Trader方法在自己的线程上运行。

broker对象负责设置trader的位置。每当交易者的一个订单被填满时,它将设置头寸。 Broker个方法在自己的线程上运行。

traderbroker都在同一个包中。职位以包私有static ConcurrentHashMap的形式实施。键是交易者对象的id。值为Integer。

包的外部是应用程序。它通过公共吸气剂间接获得交易者的头寸。

每隔几分钟,位置最多会改变一次,因此broker不会经常触及地图。但是,trader和应用程序将经常阅读。此外,我们经常有几个交易者同时阅读地图。

因此,以这种方式使用ConcurrentHashMap,我不必处理锁定和数据可见性问题? ConcurrentHashMap可以处理所有事情吗?

2。市场(买入价,卖出价,最后价格)

与位置几乎相同的情况,除了现在broker将非常频繁地更新价格(在繁忙时间每秒最多10次更新;通常是每秒几次)。 trader和应用程序仍然会频繁读取。现在,地图键是指示哪个库存或未来的代码,值是保持市场价格的对象。

它似乎工作正常,但在阅读JCIP之后,我意识到如果事情没有正确实现,程序仍然会被破坏。这本书讨论了ConcurrentHashMap,但没有明确告诉我第一部分我们不再需要手动解决的问题。 出现,在这种情况下,我没有synchronize任何内容。这是对的吗?

3 个答案:

答案 0 :(得分:3)

是的,ConcurrentHashMap负责可见性和锁定,只要:

  • map持有的值是不可变的。鉴于您的价格对象是不可变的,在您的描述中似乎是正确的;
  • 您在地图上没有必须是原子的操作,不能表示为对地图API的单次调用。例如,如果您需要“从地图读取值,执行计算并将结果返回到地图上”等操作为原子操作,则仍需要在此操作期间保持显式锁定,或者更好的是,更改应用程序以便仅使用地图API的原子操作,例如get/put/putIfAbsent

答案 1 :(得分:3)

  

所以这样使用ConcurrentHashMap,   我不需要关于锁定和工作   数据可见性? ConcurrentHashMap   照顾好一切?

这取决于地图中的内容,如果我正确阅读了您的示例,情况就像这样

static final ConcurrentMap<Integer,Integer> map = ...

class Trader{

  public int doRead(){
      map.get(someId);
   }
}
class Broker{
   public void doWrite(){
      map.put(someId,someValue);
   }
}

如果是这种情况,那么是的,所有的并发性都得到了解决。

但是,如果地图看起来像

static final ConcurrentMap<Integer,Trader> map = ..

    class Broker{
       public void doWrite(){
          map.get(someId).setPosition(somePosition);
       }
    }

这不是线程安全的,即使在放置时ConcurrentHashMap锁定,此时对象的所有并发访问都必须处理它们自己的同步。

答案 2 :(得分:2)

除非你说的是每秒超过100,000次更新/读取,否则我不会考虑使用多个线程。原因是线程安全组件比没有组件的组件花费的时间长许多倍。因此,如果一个组件需要花费5倍的时间来保证线程安全,那么你需要同时使用5个以上的线程来实现收支平衡,更不用说更快了。

当您执行相对昂贵的操作时,多个线程更有用。作为一个线程,更新头寸或价格会更有效率。