繁体   English   中英

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

[英]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;
}

第一个锁定对象是SynchronizedMapmutex字段。 第二个锁是隐式的 - 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;
}

所以,如果你在通过HashTableSynchronizedCollection ,线程访问到SynchronizedCollection将不得不采取锁在2级一次synchronized块,另一个用于同步的方法。 如果有其他线程直接使用HashTable对象,即使线程在SynchronizedCollection上获得锁定,它们也可以使用SynchronizedCollection来阻塞线程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM