Как судить, какой объект для синхронизации в потоке Java? - PullRequest
5 голосов
/ 23 марта 2012

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

synchronized(new Object()){
}

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

Ответы [ 5 ]

12 голосов
/ 23 марта 2012

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

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

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

class SomeClass {

    final private Object lock = new Object();

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

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

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

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

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

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

6 голосов
/ 23 марта 2012

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

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


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

3 голосов
/ 28 марта 2012

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

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

3 голосов
/ 23 марта 2012

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

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

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

2 голосов
/ 23 марта 2012

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...