ArrayList, Threads и synchronize - как синхронизация работает точно для нескольких потоков - PullRequest
3 голосов
/ 27 мая 2011

еще раз вопрос об ArrayList и синхронизации.

Я просто хотел бы знать, что именно делает этот фрагмент:

ArrayList<ObjectX> list = ....;

synchronized (list) {
    if (list.contains(objectxy) == false) {
      list.add(objectxy);
    }
}

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

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

Вот чего я хочу достичь. Будет ли это работать? : -)

Так что, если да, я хотел бы знать, что именно делает фрагмент. Предотвращает ли два потока одновременный доступ к этому точному коду? чтобы код был доступен только для одного потока одновременно?

Или он блокирует сам список на все время для любого потока в приложении, который в данный момент пытается получить доступ к списку - в любом месте ? (У меня нет других add () в моем коде, но многие get (), поэтому я хотел бы знать, могут ли другие потоки получать доступ к списку и получать элементы, пока другой поток обращается к приведенному выше коду).

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

Итак, вот что я хотел бы знать. Я старался отмечать свои вопросы, чтобы на них было легче отвечать. Спасибо за помощь! : -)

[РЕДАКТИРОВАТЬ] Спасибо за все ответы, которые почти все сказали то же самое! Я думаю, что теперь понятно! : -)

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

правильно? Я надеюсь на это: -)

Ответы [ 6 ]

5 голосов
/ 27 мая 2011

У вас в значительной степени есть это. synchronized не позволяет другим потокам, которые блокируют один и тот же объект list, одновременно запускать свои кодовые блоки. Он не блокирует сам объект list. Другие потоки могут получить к нему доступ, если они не синхронизируются с тем же объектом.

3 голосов
/ 27 мая 2011

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

synchronized (list) {
    // block A
}

synchronized (list) {
    // block B
}

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

2 голосов
/ 27 мая 2011

Да, только один поток может получить доступ к этому блоку кода одновременно. Все остальные потоки будут ждать, пока поток, который первым достигнет этого, не завершит выполнение блока кода.

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

1 голос
/ 27 мая 2011

Помимо согласия, что, как и в других ответах, предполагается, что он будет блокировать ТОЛЬКО один и тот же блок кода. Я думаю, что ключевая путаница у вас есть, и большинство людей имеют дело с блокировкой в ​​синхронизированном (блокировка). Вы использовали сам список в качестве блокировки в вашем случае. Однако , использующий объект в качестве блокировки и если код в объекте будет заблокирован, совершенно не имеет значения . Фактически, вы можете использовать любой объект в качестве блокировки, если это один и тот же объект. Это означает, что если у вас есть другая переменная-член с именем foo , приведенный ниже код будет работать в основном так же:

synchronized (foo) {
    if (list.contains(objectxy) == false) {
      list.add(objectxy);
    }
}

Каждый объект можно использовать как замок.

0 голосов
/ 27 мая 2011

Вы также можете использовать Вектор (синхронизированный список) или другие синхронизированные коллекции.Если вы выполняете много операций чтения, но меньше операций записи, вы можете использовать CopyOnWriteArrayList .

Но если вы часто делаете записи, это приводит к большим накладным расходам.

0 голосов
/ 27 мая 2011

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

public class ThreadSafeList {

    private ArrayList<String> list = new ArrayList<String>();


    public synchronized void addUnique(String s) {
        if (!list.contains(s)) {
            list.add(s);
        }
    }


    public synchronized List<String> getList() {
         return Collections.unmodifiableList((new ArrayList<String>(list)));
    }
}

Синхронизация гарантируется синхронизацией.

Синхронизированный метод похож на

  public void addUnique(String s) 
   synchronized(this){
   list.add(s);
  }

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

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