Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用ConcurrentHashMap消除了数据可见性问题?_Java_Concurrency_Concurrenthashmap - Fatal编程技术网

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

Java 使用ConcurrentHashMap消除了数据可见性问题?,java,concurrency,concurrenthashmap,Java,Concurrency,Concurrenthashmap,我已经通读了一遍,剩下的问题是:当我使用ConcurrentHashMap时,我还需要担心本书第一部分中讨论的哪些数据并发问题?以下是我的一个程序中的几个示例: 1。交易员的当前头寸(共享整数,其中“整数”是数学术语) 此数字表示交易者对象当前拥有的内容,并定义其状态。它必须阅读自己的职位才能知道该做什么(寻找新职位,或管理当前职位)Trader方法在它们自己的线程上运行 经纪人对象负责设置交易员的头寸。每次交易者的一个订单完成时,它都会设置仓位代理方法在它们自己的线程上运行 交易员和经纪人都在

我已经通读了一遍,剩下的问题是:当我使用ConcurrentHashMap时,我还需要担心本书第一部分中讨论的哪些数据并发问题?以下是我的一个程序中的几个示例:

1。交易员的当前头寸(共享整数,其中“整数”是数学术语)

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

经纪人对象负责设置交易员的头寸。每次交易者的一个订单完成时,它都会设置仓位<代码>代理方法在它们自己的线程上运行

交易员
经纪人
都在同一个包中。Position作为包private
静态ConcurrentHashMap
实现。这些键是交易对象的id。这些值是整数

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

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

因此,通过这种方式使用ConcurrentHashMap,我不必考虑锁定和数据可见性?ConcurrentHashMap处理所有事情

2。市场(出价、要价、最后价格)

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


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

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

  • 映射所持有的值是不可变的。你的描述似乎是正确的,因为你的价格是不变的
  • 在map上没有必须是原子的操作,不能表示为对map的API的单个调用。例如,如果您需要像“从映射中读取值、执行计算并将结果放回映射”这样的操作是原子操作,那么在此操作期间您仍然需要保持显式锁定,或者更好的是,更改应用程序,以便只使用映射API的原子操作,例如
    get/put/putIfAbsent
这样使用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);
   }
}
静态最终ConcurrentMap=。。。
阶级商人{
公共int doRead(){
map.get(someId);
}
}
阶级经纪人{
公共无效doWrite(){
map.put(someId,someValue);
}
}
如果是这种情况,那么所有的并发都会得到处理

但是如果地图看起来像

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

    class Broker{
       public void doWrite(){
          map.get(someId).setPosition(somePosition);
       }
    }
静态最终ConcurrentMap=。。
阶级经纪人{
公共无效doWrite(){
map.get(someId).setPosition(somePosition);
}
}

这不是线程安全的,即使在放置时ConcurrentHashMap会锁定,此时对象的所有并发访问都必须处理它们自己的同步
当需要执行相对昂贵的操作时,多线程更有用。更新一个职位或价格比一个帖子更有效。

我鼓励你重新回答你的问题。这假设每个人都读过这本书。这将限制您得到的响应的数量。因此,第二个示例中的问题是,我们让经纪人获取一个锁,然后向需要同一映射的锁的交易员发出一个外来调用?问题是映射是线程安全的,但映射中的任何可变对象都不是线程安全的。@Pete,正如Peter Lawrey所提到的,可变对象不是线程安全的,除非它们本身正确地同步。一旦输入CHM,就会丢失任何新的同步点(锁获取)。所有CHM GET(几乎所有)都不会获得put锁,因此,如果映射所持有的对象的字段发生了更改,其他线程可能看不到该更改。在这种情况下,使用单独的线程以逻辑方式分割代码,使维护和开发更容易。只有一点点共享的、可变的数据,所以我认为这种权衡是值得的。速度不是什么大问题,因为我没有参与被称为“HFT”的疯狂活动。如果速度不是什么大问题,我会使用一个高级锁来锁定收藏和其中的所有内容。(并确保访问速度尽可能快,无需调用IO等)这是最简单的选择。正确的,线程上下文切换的成本非常高,因此您需要确保任何工作都是有效的