зацикливание на статической сети - PullRequest
0 голосов
/ 13 марта 2011

У меня есть в моем коде:

public static Set<Long> workItemsForTasks = new HashSet<Long>();

Это веб-приложение, и во время кода пользователи могут добавлять новые элементы на карту - и я добавляю код, подобный этому:

WorkflowOperations.workItemsForTasks.add(workItem.getId());

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

 Iterator workItemsIter = service.workItemsForTasksToBMS.iterator();
   while (workItemsIter.hasNext()) {
workItemsIter.remove();

    ...
    }

Мой вопрос:

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

РЕДАКТИРОВАНИЕ

Это веб-приложение, которое принимает различные вызовы веб-службы.

В вызове A пользователи могут добавлять данные, которые в Call BI могут понадобитьсяhandle.

Итак, я определил одноэлементный класс (с помощью Spring Bean), который содержит набор данных, которые мне нужно обработать (данные являются числами), и я изменяю Set каждый раз, когда у меня есть веб-служба Вызов A... как только пользователь запрашивает веб-службу Call B - я должен собрать данные и выполнить с ними что-либо.

Ответы [ 3 ]

3 голосов
/ 13 марта 2011

Доступ к набору осуществляется одновременно из нескольких потоков?

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

Однако, если есть одновременный доступ,тогда вы делаете две вещи неправильно.Во-первых, HashSet не является потокобезопасным.Во-вторых, изменение HashSet во время итерации по нему (кроме как через Iterator) является неправильным, и (мы надеемся!) Приведет к ConcurrentModificationException.

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

private static void doMyStuff() {
    Set<Long> myWorkingSet;
    synchronized (workItemsForTasks) {
        myWorkingSet = new HashSet(workItemsForTasks);
        workItemsForTasks.clear();
    }
    for (long x : myWorkingSet) {
        // do something
    }
}

Если вы делаете что-то подобное, вы должны скрыть workItemsForTasks за методами доступа вваш класс, чтобы вы могли гарантировать правильную синхронизацию.

2 голосов
/ 13 марта 2011

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

этот код будет выполняться в многопоточной среде, поэтому то, что вы написали, не будет работать - вы получите ConcurrentModificationException

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

вы не следуете «говорите, не спрашивайте», и конкретно нарушаете LoD-F (http://pragprog.com/articles/tell-dont-ask) - это способ сказать ваш кодВскоре будет трудно понять, кто что делает.

альтернативно, чтобы взломать что-то, что в основном будет работать, используйте CopyOnWriteArraySet.

1 голос
/ 13 марта 2011

Прежде всего, я полагаю, когда вы сказали карту, вы на самом деле имели в виду Set .Согласно Java Doc ,

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

Потоковая реализация HashSet будет выглядеть так:

Set s = Collections.synchronizedSet(new HashSet(...));

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

Set workItemsForTasks = Collections.synchronizedSet(new HashSet());
synchronized(workItemsForTasks) {
Iterator workItemsIter  = workItemsForTasks.iterator(); //Must be in synchronized block
while (workItemsIter.hasNext())
    //Do Something
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...