【问题标题】:TreeMap - Synchronization Documentation ExplanationTreeMap - 同步文档说明
【发布时间】:2017-05-02 15:22:44
【问题描述】:

TreeMap javadoc 有以下部分,我无法理解下面部分的最后一行。这是否意味着创建一个锁并将地图修改逻辑移动到一个同步块或其他东西中。只有结构修改需要同步,访问是线程安全的。

请注意,此实现不同步。

如果多个线程同时访问一个映射,并且至少有一个线程在结构上修改了映射,则它必须在外部同步。 (结构修改是添加或删除一个或多个映射的任何操作;仅更改与现有键关联的值不是结构修改。)This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be "wrapped" using the Collections.synchronizedSortedMap method.

【问题讨论】:

  • 是的,会的。
  • @MikeNakis 如果线程只是操作内部的值而不修改结构,那么它在非同步 Map 中是线程安全的吗?

标签: java javadoc


【解决方案1】:

基本上,Javadoc 相当混乱,因为如果您完全修改映射(包括当您只是更改与现有键关联的值时),您希望在几乎所有情况下同步所有操作。 (几乎)唯一不需要同步的情况是地图在发布后是完全只读的。

现在,为什么 Javadoc 会说 If ... at least one of the threads modifies the map structurally - 这是因为如果您只是更改与现有键关联的值,那么可能发生的最糟糕的事情就是您在未指定的时间内读取了陈旧的值。相反,如果在没有同步的情况下进行结构更改,则可能会发生更糟糕的事情(例如NullPointerExceptions,无限循环)。

然而,同步或使用并发集合几乎总是比允许陈旧值更好。

【讨论】:

    【解决方案2】:

    是不是说要创建锁,移动地图修改逻辑 一起进入一个同步块或其他东西。 是否只有结构修改需要同步和 访问是线程安全的。

    不,这还不够。
    仅同步进行结构修改的处理是不够的,因为如果读取映射的方法未同步,则可以与同步方法同时调用该方法。
    因此,对 Map 的访问可以与读取操作和结构修改操作同时进行。这是不可取的。

    最后,如果多个线程同时访问map,并且至少有一个线程修改了map结构,则意味着所有对map的访问都应该同步。

    【讨论】:

    • 更不用说只“读取”数据结构的操作实际上可能会改变它们(例如展开树)。你不知道(而且你不应该知道)get() 的实现可能会在幕后做什么。
    • @biziclop 感谢您的反馈。我发现执行 Map 修改的公共读取方法是一个糟糕的 API。请问您有 TreeMap 或 Java Collection 中的示例吗?
    • 正如我所说,这就是伸展树的真正工作方式。您搜索的最后一个元素将被移动到树的根部,以加快对同一元素的后续查找。内置的TreeMap 不会,但实现在get() 中更改其内部状态是完全合法的,只要它不影响从外部可见的任何内容。
    • 在概念上确实是一个展开树。我完全同意这样做是合法的,但我认为为了并发问题,应该指定方法的 API。例如:同步一个经典的HashMap,它只在客户端可以访问时执行读取,这是一个代价高昂的权衡,应该避免。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    • 2012-08-28
    相关资源
    最近更新 更多