![](/img/trans.png)
[英]Difference between Hashtable and Collections.synchronizedMap(HashMap)
[英]What happens when we pass hashtable inside Collections.synchronizedMap()
今天我在采访中提出了一个问题。 问题是Collections.synchronizedMap()用于同步地图,默认情况下不像hashmap那样是线程安全的。 他的问题是,我们可以在这个方法中传递任何类型的地图。 那么当我们在此方法中传递哈希表时会产生什么影响,因为哈希表默认是同步的。
映射的行为将是相同的,但性能将受到影响,因为每个方法将获取两个同步锁而不是一个。
例如,考虑在结果映射上调用方法size()
。 Collections.SynchronizedMap
类中的实现如下所示:
public int size() {
synchronized(mutex) {return m.size();} // first lock
}
...其中, m.size()
调用Hashtable
的实现:
public synchronized int size() { // second lock
return count;
}
第一个锁定对象是SynchronizedMap
的mutex
字段。 第二个锁是隐式的 - Hashtable
实例本身。
您将有两个同步级别:一个在同步映射本身级别,由互斥对象实现,另一个在包装实例级别:
public boolean isEmpty() {
// first level synchronization
synchronized(mutex) {
// second level synchronization if c is a Hashtable
return c.isEmpty();
}
}
不需要额外的同步,可能导致性能降低。
另一个影响是,您将无法使用Hashtable
API,如Hashtable#elements
因为包装的集合现在严格来说是一个Map
实例。
它将从java.util.Collections
包装到SynchronizedMap
java.util.Collections
:
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
return new SynchronizedMap<>(m);
}
synchronizedMap()
方法不区分传递给它的Map
的类型。
“他的问题是,但我们可以通过这种方法传递任何类型的地图。”
答案是肯定的,因为SynchronizedMap
的构造函数接受其签名中的每个Map
。
“那么当我们在此方法中传递哈希表时会产生什么影响,因为哈希表默认是同步的”
答案是:我们对ConcurrentHashMap
表示无知,这很可能是使用的工具而不是阻塞实现。
如果您在SynchronizedCollection
看到代码。 这些方法会将调用委托给底层集合,但会在调用之上添加synchronized块,就像这样
public int size() {
synchronized (mutex) {return c.size();}
}
在HashTable
类中,大小的实现看起来像这样
public synchronized int size() {
return count;
}
所以,如果你在通过HashTable
来SynchronizedCollection
,线程访问到SynchronizedCollection
将不得不采取锁在2级一次synchronized块,另一个用于同步的方法。 如果有其他线程直接使用HashTable对象,即使线程在SynchronizedCollection
上获得锁定,它们也可以使用SynchronizedCollection
来阻塞线程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.