我正在编写一个代码,它在构造函数中使用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
在不同实例上使用时如何同步?
让问题更广泛,如何在全球范围内同步实例?
答案 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在程序中依赖于其线程安全但不依赖于它 同步细节。