2014-11-07 3 views
6

Сегодня я задал вопрос в своем интервью. Вопрос в том, что Collections.synchronizedMap() - это , используемый для синхронизации карты, которые по умолчанию не являются потокобезопасными, как hashmap. Его вопрос в том, что мы можем передать любую карту внутри этого метода. Итак, каков эффект, когда мы передаем хэш-таблицу внутри этого метода, потому что хэш-таблица по умолчанию синхронизирована.Что происходит, когда мы передаем хеш-таблицу внутри Collections.synchronizedMap()

ответ

0

Если вы видите код в SynchronizedCollection.Методы делегируют вызов к основной коллекции, но при добавлении синхронизируются блок сверху вызова что-то вроде этого

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

Реализации размера выглядит в HashTable классе

public synchronized int size() { 
    return count; 
} 

Таким образом, если вы переходите в HashTable в SynchronizedCollection, поток, обращающийся к SynchronizedCollection, должен будет занять блокировки на 2 уровнях один раз для синхронизированного блока, а другой для синхронизированного метода. Если есть другие потоки, напрямую связанные с объектом HashTable, они могут блокировать потоки, используя SynchronizedCollection, даже когда поток получил блокировку на SynchronizedCollection.

+0

Копия ответа Natix? – user219882

+1

Я написал ответ параллельно с ним, я думаю, я не уверен, почему он приведен ниже, плюс я дал одну причину, почему бы не сделать это. –

1

Это будет получить завернутые в SynchronizedMap из java.util.Collections:

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) { 
    return new SynchronizedMap<>(m); 
} 

synchronizedMap() метод не делает различия между типами Map с перешедших в него.

2

Вы бы два уровня синхронизации: один на уровне самой синхронизированной карты, реализуемый объектом мьютекса, и один на уровне обернутых например:

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

Дополнительная синхронизация не требуется и может привести к снижению производительности.

Еще один эффект заключается в том, что вы не сможете использовать API от Hashtable, как Hashtable#elements, так как обернутая коллекция теперь строго представляет собой экземпляр Map.

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.

0

«Его вопрос только в том, что мы можем передать любую карту внутри этого метода».

Ответ да, потому что конструктор SynchronizedMap принимает каждое Map в его подписи.

«Так что эффект, когда мы передаем хэш-таблицу внутри этого метода, поскольку Хеш по умолчанию синхронизирована»

Ответ: Мы показываем невежество в ConcurrentHashMap, который, скорее всего, инструмент будет использоваться вместо реализации блокировки.

Смежные вопросы