如何同步传递给多个地方的实例?

时间:2014-03-26 04:52:15

标签: java multithreading synchronization

我正在编写一个代码,它在构造函数中使用Map,并将其分配给实例变量。使用此实例变量map的任何方法都是同步的。

class Foo {

   Map<Int, Int> map;

   Foo ( Map<Int, Int> map ) {
       this.map = map;
   }

   synchornized void put(int x, int y) {
       map.put(x, y);
   }

}

但是 - 客户端创建了多个Foo实例,并将相同的地图实例传递给每个实例。

Map<Int, Int> map = new HashMap<Int, Int>();
new Foo(map);
new Foo(map);

map在不同实例上使用时如何同步? 让问题更广泛,如何在全球范围内同步实例?

4 个答案:

答案 0 :(得分:1)

您应该同步map,而不是foo实例本身。

即。

void put(int x, int y) {
    synchronized (map) {
       map.put(x, y);
    }
}

编辑:

这里的关键点是,您需要了解同步的概念,并确定&#34;资源&#34;这是共享的,需要同步。在您的情况下,共享资源是Map,而不是Foo实例本身。同时访问Map会导致问题,因此您应该同步的是共享资源 - Map本身。

还有其他一些建议使用ConcurrentHashMap的答案。 ConcurrentHashMap在某些情况下可以提供帮助,但它不会涵盖同步块的可能性(或使用其他类型的锁定机制)

ConcurrentMap解决了提供一些&#34;复杂&#34;映射的操作过去需要多次访问,因此需要在Map上显式锁定。 ConcurrentHashMap更进一步,使线程安全无锁读取等。

但是,没有必要解决问题。

假设我需要在Map上执行的操作不是提供的操作: 例如

synchronized(map) {
    if (map.contains("key1")) {
        map.put("key3", val1);
    } else if (map.contains("key2")) {
        map.put("key3", val);
    }
 }

,然后我需要显式锁定(在这种情况下,ConcurrentHashMap可能会更糟,因为它不允许我执行显式同步)

答案 1 :(得分:1)

我想补充以前的答案。

您所描述的模式的问题,没有进一步的背景,是您不知道实际发送的内容或类外的内容。你唯一知道的是它实现了Map。

如果你需要保护(同步)这个地图的输入,那么模式就会被破坏,因为调用者,即首先向你提交地图的人,也可能已将其提交给其他类,或者可能是以其他方式操纵它,没有锁。

唯一可以确定您操作的地图是否得到妥善保护的唯一方法是,如果您自己拥有它并确保不将其引用泄漏给其他人。

这意味着您应该在首次获取时将复制提交的地图复制到私人地图中。这样,没有人知道,没有人可以操纵它。

class Foo {
  private final Map<Integer, Integer> map;

  Foo(Map<Integer, Integer> map) {
    this.map = new HashMap<Integer, Integer>(map);
  }
}

然后,您还可以利用java中的现代锁定样式:

class Foo {
  private final Map<Integer, Integer> map;
  private final ReentrantReadWriteLock mapLock = new ReentrantReadWriteLock();

  Foo(Map<Integer, Integer> map) {
    this.map = new HashMap<Integer, Integer>(map);
  }

  public Integer put(Integer k, Integer v) {
    try {
      mapLock.writeLock().lock();
      return map.put(k, v);
    } finally {
      mapLock.writeLock().unlock();
    }
  }

  public Integer get(Integer k) {
    try {
      mapLock.readLock().lock();
      return map.get(k);
    } finally {
      mapLock.readLock().unlock();
    }
  }
}

安全 - 复制您的输入并且不要泄露您的参考文献!

答案 2 :(得分:0)

您可以使用ConcurrentHashMap - 这种类型的Map是线程安全的。

或者,在类上进行同步,以便该类的任何实例共享相同的锁。

或者,在地图上同步。

答案 3 :(得分:0)

使用ConcurrentHashMap代替HashMap

  

支持检索的完全并发和可调整的哈希表   预期的更新并发性。本课程遵循相同的功能   规范为Hashtable,包括方法版本   对应于Hashtable的每种方法。但是,尽管如此   操作是线程安全的,检索操作不需要   锁定,并没有任何支持锁定整个表   一种阻止所有访问的方法。这个类可以完全互操作   Hashtable在程序中依赖于其线程安全但不依赖于它   同步细节。