【问题标题】:safe use of iterator in syncronized collections在同步集合中安全使用迭代器
【发布时间】:2014-05-27 07:41:46
【问题描述】:

在有关 synchronizedMap 的教程中,我遇到了以下代码(教程中的 cmets):

Map m = Collections.synchronizedMap(new HashMap());
...
Set s = m.keySet();  // Needn't be in synchronized block
...
synchronized(m) {  // Synchronizing on m, not s!
    Iterator i = s.iterator(); // Must be in synchronized block
    while (i.hasNext())
          foo(i.next());
}

我在源代码中看到迭代器方法没有被同步部分包装。没关系。

我害怕得到意想不到的东西

Set s = m.keySet();  
// Could happen something unexpected here ?
synchronized(m) { 

请说明为什么这段代码是安全的?

 synchronized(m) {  // Synchronizing on m, not s!
        Set s = m.keySet();  // Needn't be in synchronized block
        Iterator i = s.iterator(); // Must be in synchronized block
        while (i.hasNext())
              foo(i.next());
    }

这种同步是否过度?

【问题讨论】:

    标签: java collections iterator synchronization


    【解决方案1】:

    虽然Collections.synchronizedMap() 保证包装映射上的每个操作都是线程安全的,但它不保证对其进行迭代。当您在迭代时在地图上进行同步时,您保证了另一个线程在 1 个线程对其进行迭代时无法访问该地图(毕竟,您要确保以原子方式对其进行迭代)。

    如果没有这种同步,另一个线程可以在i.hasNext() while 循环之间执行一个或多个操作。

    实现是synchronizedMap() 包装器在集合本身上同步(在您的代码m 中),因此使用synchronized(m) 获取对象监视器可确保在完全执行迭代之前另一个线程无法访问它。

    【讨论】:

    • Set s = m.keySet();Iterator i = s.iterator()之间的操作
    • 你为什么害怕他们?如果密钥集有更改,它们将反映在s 中。如果你想避免这种情况,你应该在取出密钥集之前同步m
    • 我无法想象可能发生的所有变化。
    • 所有与键集相关的更改。添加和删​​除项目主要是我想说的。
    猜你喜欢
    • 2013-03-04
    • 2010-12-19
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    • 2011-05-29
    • 1970-01-01
    • 2021-10-22
    • 2010-12-26
    相关资源
    最近更新 更多