Список синхронизированных Java


У меня есть предварительно заполненный список массивов. И у меня есть несколько потоков, которые будут удалять элементы из списка выбора. Каждый поток вызывает метод remove ниже и удаляет один элемент из списка. Следующий код дает мне последовательное поведение ?

ArrayList<String> list = Collections.synchronizedList(new ArrayList<String>());

void remove(String item)
{
     do something; (doesn't work on the list)
     list.remove(item);
}

спасибо!

7 59

7 ответов:

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

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

List list = Collections.synchronizedList(new ArrayList());
    ...
synchronized (list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());
}

или, вы можете использовать CopyOnWriteArrayList который медленнее для записи, но не имеет этой проблемы.

Это должно быть хорошо, если вам не требуется, чтобы метод "remove" был атомарным.

кроме того, убедитесь, что вы синхронизируете в списке при повторении:

synchronized(list) {
    for (Object o : list) {}
}

Как отметил Петр Lawrey, CopyOnWriteArrayList может сделать вашу жизнь более легкая и может обеспечить более лучшее представление в сильно одновременной окружающей среде.

С Collections#synchronizedList(List) документация

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

вы можете иметь 2 различных проблемы со списками:
1) Если вы делаете модификацию в итерации, даже если в среде моно-потока, у вас будет ConcurrentModificationException, как в следующем примере :

List<String> list = new ArrayList<String>();
for (int i=0;i<5;i++)
   list.add("Hello "+i);

for(String msg:list)
   list.remove(msg);

поэтому, чтобы избежать этой проблемы, вы можете сделать :

for(int i=list.size()-1;i>=0;i--)
   list.remove(i);

2) второй проблемой может быть многопоточная среда. Как уже упоминалось выше, вы можете использовать synchronized(list), чтобы избежать исключений.

Это даст последовательное поведение для операций добавления/удаления. Но во время итерации вы должны явно синхронизироваться. см. ссылку

Да, он будет работать нормально, как у вас synchronized список . Я бы предложил вам использовать CopyOnWriteArrayList.

CopyOnWriteArrayList<String> cpList=new CopyOnWriteArrayList<String>(new ArrayList<String>());

    void remove(String item)
    {
         do something; (doesn't work on the list)
                 cpList..remove(item);
    }
synchronized(list) {
    for (Object o : list) {}
}