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

发布于 2024-10-09 18:35:15 字数 1099 浏览 0 评论 0原文

我已经通读了 Java 并发实践,并留下了这个问题:当我使用 ConcurrentHashMap 时,什么数据本书第一部分中讨论的并发问题我还需要担心吗?以下是我的一个程序中的几个示例:

1.交易者的当前仓位(共享整数,其中“整数”是数学术语)

此数字代表交易者对象当前拥有的内容并定义其状态。它必须读取其位置才能知道要做什么(寻找开始一个新位置,或管理当前位置)。 Trader 方法在自己的线程上运行。

经纪人对象负责设置交易者的头寸。每次执行交易者的订单之一时,它都会设置头寸。 Broker 方法在自己的线程上运行。

交易者经纪商都在同一个包中。位置被实现为包私有静态ConcurrentHashMap。键是交易者对象的 ID。值为整数。

包的外部是应用程序。它通过公共 getter 间接获取交易者的头寸。

位置最多每隔几分钟改变一次,因此经纪人不会经常接触地图。然而,交易者和应用程序会经常阅读。此外,我们经常有几个交易者同时阅读地图。

因此,以这种方式使用 ConcurrentHashMap,我不必考虑锁定和数据可见性? ConcurrentHashMap 负责一切?

2.市场(买价、卖价、最新价格)

与仓位的情况几乎相同,只是现在经纪商 会非常频繁地更新价格(在繁忙时间每秒最多更新 10 次;通常每秒几次)。 交易者和应用程序仍然会频繁读取。映射键现在是指示哪个股票或期货的代码,而值是保存市场价格的对象。

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

I've read through Java Concurrency in Practice and am left with this question: when I use a ConcurrentHashMap, what data concurrency issues discussed in Part One of the book do I still need to worry about? Here are a couple of examples from one of my programs:

1. Current position of a trader (a shared integer where 'integer' is the mathematical term)

This number represents what a trader object currently owns and defines its state. It must read its position to know what to do (look to start a new position, or manage the current one). Trader methods run on their own thread.

A broker object is in charge of setting the trader's position. It will set the position each time one of the trader's orders is filled. Broker methods run on their own thread.

Both the trader and broker are in the same package. Position is implemented as a package-private static ConcurrentHashMap. The keys are id's of the trader objects. The values are Integer.

External to the package is the application. It gets the traders' positions indirectly with a public getter.

Positions will change at most once every few minutes, so the broker won't touch the map very often. However, the trader and application will frequently read. In addition we often have several traders reading the map concurrently.

So using a ConcurrentHashMap this way, I don't have to work about locking and data visibility? The ConcurrentHashMap takes care of everything?

2. The market (bid, ask, last prices)

Pretty much the same situation as position, except now the broker will very frequently update the prices (up to 10 updates a second during busy times; normally a few times a second). The trader and application still do frequent reads. The map keys now are codes indicating which stock or future, and the values are objects which hold the market prices.

It seems to work okay, but after reading JCIP, I realize the program can still be broken if things are not implemented correctly. The book talks about the ConcurrentHashMap but doesn't explicitly tell me what issues from Part I we no longer have to address manually. It appears that I don't have to synchronize anything in this case. Is that correct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

惯饮孤独 2024-10-16 18:35:15

因此以这种方式使用 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 在放置时锁定,此时对象的所有并发访问都必须处理自己的同步。

So using a ConcurrentHashMap this way,
I don't have to work about locking and
data visibility? The ConcurrentHashMap
takes care of everything?

This depends on what is in the Map, if I read your example correctly the situation looks like this

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

class Trader{

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

If that is the case, then yes all the concurrency is taken care of.

However if the map looks like

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

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

This is NOT thread safe, even though the ConcurrentHashMap locks when you put, all concurrent access of objects at this point must handle their own synchronization.

鸠书 2024-10-16 18:35:15

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

  • 映射保存的值是不可变的。鉴于您的价格对象是不可变的,您的描述似乎是正确的;
  • 您在地图上没有必须是原子的操作,并且不能表示为对地图 API 的单个调用。例如,如果您需要像“从映射中读取值,执行计算,然后将结果放回到映射上”这样的操作是原子的,那么您仍然需要在此操作期间保持显式锁定,或者更好的是,更改应用程序,这样您只需使用地图API的原子操作,例如get/put/putIfAbsent

Yes, ConcurrentHashMap takes care of visibility and locking as long as:

  • values held by map are immutable. Seems to be true in your description, given that your prices objects are immutable;
  • you don't have operations on map which must be atomic and can't be expressed as single calls to map's API. For example if you need operation like 'read value from map, perform calculation, and put the result back on the map' to be atomic, you still need to hold explicit lock during this operation, or, better yet, change application so you only use atomic operations of map API such as get/put/putIfAbsent.
近箐 2024-10-16 18:35:15

除非您谈论的是每秒超过 100,000 次更新/读取(非常粗略的指南),否则我不会考虑使用多个线程。原因是线程安全组件比非线程安全组件花费的时间要长很多倍。因此,如果一个组件需要 5 倍的时间才能实现线程安全,那么您需要同时使用 5 个以上的线程才能实现收支平衡,更不用说速度更快了。

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

Unless you are talking about over 100,000 updates/reads per second (very rough guide) I wouldn't consider using multiple threads. The reason is that thread-safe components take many times longer than components which are not. So if a component take 5x longer to be thread safe, you need to be using over 5 threads concurrently to break even, never mind go faster.

Multiple threads are much more useful when you have relatively expensive operations to perform. Updating a position or price is much more efficient as one thread.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文