2012-03-23 5 views
5

Я думаю, что я могу использовать любой объект для синхронизации в виде блока, такие как:Как судить, какой объект должен быть синхронизирован в java-потоке?

synchronized(new Object()){ 
} 

, но я часто вижу синхронизированной один HashMap, когда нужно Hashmap поточно safe.but Я думаю, что я могу использовать один другой объект вместо хэш-карты. Итак, какой объект лучше всего синхронизироваться?

ответ

12

Выполнение synchronized (new Object()) { ... } бесполезно, поскольку ни одна другая нить не сможет схватить объект, который заблокирован в любом случае.

Вы должны синхронизировать объект, «охраняющий» ресурс. Очевидно, что если нескольким потокам нужен доступ к одному и тому же ресурсу, объект, защищающий ресурс, должен быть доступен для обоих потоков.

Возможно, вы видели это:

class SomeClass { 

    final private Object lock = new Object(); 

    void method() { 
     ... 
     synchronized (lock) { 
      ... 
     } 
     ... 
    } 
} 

Это, однако, очень отличается от выполнения synchronized (new Object()), так как в коде выше, тот же объект используется для всех потоков, выполняющихся метод.

, но я часто вижу синхронизированной один HashMap, когда нужно Hashmap быть нить safe.but Я думаю, что я могу использовать один другой объект вместо HashMap. Итак, какой объект лучше всего синхронизирован?

Правильно, если хеш-карта является ресурсом, который будет использоваться для нескольких потоков, то для синхронизации является общим для этого объекта.

synchronized (someHashMap) { 
    ... use someHashMap in a thread safe way ... 
} 

И да, вы могли бы точно так же синхронизировать на некотором поле члена lock = new Object(), а также. Фактически, синхронизация с использованием выделенного объекта блокировки иногда предпочтительна, поскольку она не мешает синхронизованным методам защищаемого объекта.

+0

большое спасибо вам! – jiafu

+0

Добро пожаловать :-) – aioobe

6

Синхронизация с использованием нового объекта каждый раз не делает ничего более надежным в потоке. Вам нужно повторно использовать тот же объект синхронизации каждый раз.

Другое, что вы можете использовать другой «объект синхронизации», чем структура данных, которую вы блокируете (но вам нужно убедиться, что вы используете ту же ссылку везде!;)).


В самом деле, многие используют специальный объект синхронизации (например private final Object sync = new Object()) внутри объекта, так как синхронизация this может быть опасно, если другой поток может запереть объект где-нибудь еще в коде.

+0

Огромное спасибо вам. ты имеешь в виду? Я могу использовать любой объект в качестве синхронизированного объекта, но я должен сохранить синхронизированный объект в другом коде, если я хочу, чтобы это безопасно? – jiafu

+0

Вам нужно будет защитить структуру данных, к которой вы прикасаетесь несколькими потоками, с одним и тем же механизмом блокировки. Если вы используете блок «synchronized», который должен блокировать то же самое задание. – dacwe

+2

+1 Вы должны быть осторожны при синхронизации с известными классами, а не с выделенными объектами, если не знаете точно, что делает этот класс. Если этот класс имеет встроенную синхронизацию, вы можете вызвать тупик, противоречащий внутреннему коду этого класса, который синхронизируется с самим собой. –

2

Это действительно не имеет значения, если вы используете один и тот же каждый раз. Я лично предпочитаю использовать фактический объект, который нуждается в синхронизации (например, ваш HashMap), потому что он более четко передает, что я его синхронизирую, а другой экземпляр объекта (с возможными беспорядочными переменными) не нужен.

И обратите внимание, что если вы на самом деле с помощью:

synchronized(new Object()) { 
    // ... 
} 

то, что вы делаете это неправильно, так как new Object() создает новый объект каждый раз; вам нужно сохранить ту же ссылку для правильной синхронизации.

+0

большое спасибо вам! – jiafu

3

Прежде всего, было бы неплохо сделать synchronized(new Object()), потому что каждый поток создавал бы свои собственные объекты, поэтому синхронизация была бы бессмысленной.

В примере, где вы хотите синхронизировать доступ к существующему объекту, синхронизация на этом объекте имеет смысл. Невозможно создать другой объект для синхронизации.

Однако, если вы хотите сделать что-то более интересное, чтобы увеличить параллелизм - например, разделите возможные ключи карты на несколько наборов и защитите каждый из этих наборов другой блокировкой, а затем создайте отдельный объекты для синхронизации могут быть полезны. Но я бы не стал беспокоиться о чем-то подобном, пока вы действительно не определили проблему производительности, которую нужно решить.

+0

-1: «Нет никакой пользы для создания какого-либо другого объекта для синхронизации». Если вы синхронизируете с существующим объектом, который синхронизируется с самим собой в своих собственных методах, вы можете вызвать тупик, не осознавая этого. –

+0

@ ErickRobertson - да? Тупик требует, чтобы блокировки были приобретены на двух разных объектах. Если поток получает блокировку на объекте A, затем вызывает синхронизированный метод в этом объекте, он уже содержит блокировку, поэтому нет проблемы. –

+0

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

3

Никто, кажется, не упомянул об этом, но в зависимости от ваших требований, используя объект, защищенный потоком, в первую очередь может позволяет удалить всю логику блокировки.

В случае HashMap существует ConcurrentHashMap, который является поточно-безопасной версией с несколькими дополнительными атомными операциями (putIfAbsent и т. Д.).

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