当我们在Collections.synchronizedMap()中传递哈希表时会发生什么

时间:2014-11-07 11:30:00

标签: java spring collections

今天我在采访中提出了一个问题。 问题是Collections.synchronizedMap()是 用于同步地图,默认情况下不像hashmap那样是线程安全的。 他的问题是,我们可以在这个方法中传递任何类型的地图。 因此,当我们在此方法中传递哈希表时,效果是什么,因为哈希表默认是同步的。

5 个答案:

答案 0 :(得分:3)

地图的行为将是相同的,但性能会受到影响,因为每个方法将获得两个同步锁而不是一个。

例如,考虑在结果地图上调用方法size()Collections.SynchronizedMap类中的实现如下所示:

public int size() {
    synchronized(mutex) {return m.size();} // first lock
}

...其中,m.size()调用Hashtable中的实现:

public synchronized int size() { // second lock
    return count;
}

第一个锁定对象是mutex中的SynchronizedMap字段。第二个锁是隐式的 - Hashtable实例本身。

答案 1 :(得分:2)

您将有两个同步级别:一个在同步映射本身级别,由互斥对象实现,另一个在包装实例级别:

public boolean isEmpty() {
    // first level synchronization
    synchronized(mutex) {
        // second level synchronization if c is a Hashtable
        return c.isEmpty();
    }
}

不需要额外的同步,可能导致性能下降。

另一个影响是,您将无法使用Hashtable之类的Hashtable#elements来使用API​​,因为包装的集合现在严格来说是Map个实例。

答案 2 :(得分:1)

它将从SynchronizedMap

包裹到java.util.Collections
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
    return new SynchronizedMap<>(m);
}

synchronizedMap()方法无法区分传递给它的Map类型。

答案 3 :(得分:0)

“他的问题是,但我们可以在这种方法中传递任何类型的地图。”

答案是肯定的,因为SynchronizedMap的构造函数接受其签名中的每个Map

“那么当我们在此方法中传递哈希表时会产生什么影响,因为哈希表默认是同步的”

答案是:我们对ConcurrentHashMap表示无知,这很可能是使用的工具,而不是阻塞实现。

答案 4 :(得分:0)

如果您在SynchronizedCollection中看到代码。这些方法会将调用委托给底层集合,但会在调用之上添加synchronized块,如此

public int size() {
 synchronized (mutex) {return c.size();}
}

HashTable

中的大小实现如下所示
public synchronized int size() {
    return count;
}

因此,如果您将HashTable传递给SynchronizedCollection,则访问SynchronizedCollection的线程必须为同步块一次锁定2级,而对于同步方法则需要另一级锁。 如果有其他线程直接使用HashTable对象,即使线程在SynchronizedCollection上获得锁定,它们也可以使用SynchronizedCollection阻塞线程。