2010-01-28 3 views
3

Я использую Collections.synchronizedCollection в Java для защиты набора, который, как мне известно, получает доступ одновременно несколькими потоками. Java API предупреждает:synchronizedCollection и содержит - мне нужно синхронизировать вручную?

«Крайне важно, чтобы пользователь вручную синхронизировать возвращенной коллекции при переборе над ним:

Collection c = Collections.synchronizedCollection(myCollection); 
    ... 
    synchronized(c) { 
     Iterator i = c.iterator(); // Must be in the synchronized block 
     while (i.hasNext()) 
     foo(i.next()); 
    } 

»

Если я использую c.contains(obj), что поточно-? Внутри, очевидно, это итерация по коллекции и наблюдение, если какой-либо из объектов в ней равен obj. Мой инстинкт состоит в том, чтобы предположить, что это, вероятно, синхронизировано (казалось бы, это серьезный провал, если нет), но, учитывая предыдущие проблемы с синхронизацией, кажется разумным дважды проверить, и поиск Google ответов на это не превратился все что угодно.

ответ

7

Само по себе звонок contains безопасен.

Проблема в том, что часто проверяется, содержит ли коллекция элемент , тогда делает что-то в коллекции на основе результата.

Скорее всего, испытание и действие следует рассматривать как единую атомную операцию. В этом случае должна быть получена блокировка коллекции, и обе операции должны выполняться в блоке synchronized.

+0

Это хороший момент; Я не считал, что добавляю к нему ценность, если ее там нет. В этом случае кажется очевидным, что мне придется вручную синхронизировать. – DivineWolfwood

+2

И в таком случае, почему бы просто не добавить его? Что делает базовая реализация? Например, для HashSet a содержит, а затем добавление делает двойную работу только добавить. В вашем случае, независимо от добавления реализации Set, это будет атомная операция в отношении синхронизации, и ваш код add() должен обрабатывать дубликаты в любом случае (даже если сам он просто проверяет contains()), чтобы правильно выполнить контракт Добавить(). – PSpeed

+0

@PSpeed: Отличное предложение. Это избавляет меня от необходимости выполнять синхронизацию, потому что я все равно добавляю ее. – DivineWolfwood

1

Это безопасно, потому что contains сам синхронизирован.

+0

Спасибо: из любопытства, как вы это подтвердите? Разве это просто общеизвестно, что эти синхронизированные классы выполняются так, добавляя синхронизацию ко всем методам? Я пытался просмотреть файл .class для коллекций, но ничего не мог извлечь из этого. – DivineWolfwood

+0

@DivineWolfwood Чтобы дважды проверить, у меня есть источники JDK, поэтому я щелкнул и посмотрел. – daveb

+1

@DivineWolfwood: Помимо изучения исходного кода, единственный способ определить это из JavaDoc. Вот почему так важно документировать параллельное поведение и требования к классам - то, что все еще продолжается. –

2

Collections.synchronizedCollection() будет возвращать коллекцию thread safe, что означает любой звонок по методу thread safe сам по себе. Это зависит от того, что вы хотите. Если вы хотите вызвать пару методов, java не может сделать поток потокобезопасным вместе.

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