Ассоциативный? Не без некоторой работы, но можно использовать универсальные селекторы:
var items = new Array();
$('#form_id:input').each(function (el) {
items[el.name] = el;
});
Если вы создали LinkedHashMap с accessOrder = true, то LinkedHashMap.get () фактически изменяет LinkedHashMap, поскольку он сохраняет последнюю доступную запись в начале связанного списка записей. Возможно, что-то вызывает get (), пока список массивов копирует его с помощью Iterator.
Are those all function you have in your wrapper? Because this exception could be thrown while you somehow iterating over collection in another place. And I guess you synchronized method with potential obvious race condition, but probably have missed less obvious cases. Here the reference to exception class docs.
This exception does not normally have anything to do with synchronization - it is normally thrown if a a Collection is modified while an Iterator is iterating through it. AddAll methods may use an iterator - and its worth noting that the posh foreach loop iterates over instances of Iterator too.
e.g:
for(Object o : objects) {
objects.remove(o);
}
is sufficient to get the exception on some collections (e.g ArrayList).
James
Я не думаю, что ваш set ()
/ get ()
синхронизируются с тем же монитором, что и rebuild ()
. Это позволяет кому-то вызывать set / get во время выполнения проблемной строки, особенно при итерации по набору ключей internalMap во время вызова addAll ()
(внутренняя реализация, которая отображается через трассировку стека).
Вместо синхронизации set ()
, Вы пробовали что-то вроде:
public void set(SomeKey key, SomeValue val) {
synchronized(this) {
internalMap.put(key, val); // or whatever your get looks like
}
}
Я не думаю, что вам вообще нужно синхронизировать get ()
, но если вы настаиваете:
public SomeValue get(SomeKey key) {
synchronized(this) {
internalMap.get(key); // or whatever your get looks like
}
}
На самом деле, я думаю, что вам лучше отключена синхронизация с internalMap
вместо this
. Также не помешает сделать internalMap
volatile
, хотя я не думаю, что это действительно необходимо, если вы уверены, что set ()
/ get ()
/ rebuild ()
- единственные методы, напрямую обращающиеся к internalMap, и все они получают доступ к нему синхронизированным образом.
private volatile Map internalMap ...
Из Javadoc:
Если несколько потоков обращаются к связанной хэш-карте одновременно, и хотя бы один из потоков структурно модифицирует карту, она должна быть синхронизирована извне. Обычно это достигается путем синхронизации некоторого объекта, который естественным образом инкапсулирует карту. Если такого объекта не существует, карту следует «обернуть» с помощью метода Collections.synchronizedMap. Лучше всего это делать во время создания, чтобы предотвратить случайный несинхронизированный доступ к карте:
Map m = Collections.synchronizedMap (new LinkedHashMap (...));
Для вас может быть безопаснее фактически обернуть LinkedHashMap вместо того, чтобы требовать от вас расширения. Таким образом, ваша реализация будет иметь внутренний элемент данных, который является картой, возвращаемой Collections.synchronizedMap (new LinkedHashMap (...)).
Подробности см. В документации по коллекциям: Collections.synchronizedMap
Является ли internalMap статическим? У вас может быть несколько объектов, каждый из которых блокируется на this
, объект, но не обеспечивает правильную блокировку на вашем static internalMap.
Try removing the synchronized keyword from the set() and get() methods, and instead use a synchronized block inside the method, locking on internalMap; then change the synchronized blocks on the rebuild() method to lock on the internalMap as well.
that is strange. I cant see any way that the exception is being thrown at the location you are identifying (in the default implmentation in Java 6). are you getting a ConcurrentModificationException in the ArrayList or the HashMap? have you overridden the keySet()
method in your HashMap
?
edit my mistake - the ArrayList will force the KeySet to iterate (AbstractCollection.toArray() will iterate over its keys)
there is somewhere in the code that is allowing you to update your internal map that is not synchronized.
Во время итерации ключей из-за
keysCopy.addAll(internalMap.keySet());
Вы решили, что некоторые записи могут быть удалены из LinkedHashMap?
Метод removeEldestEntry может быть либо возвращает истину, либо изменяет карту, тем самым нарушая итерацию.
попробуйте следующее:
public void rebuild(){
/* initialization stuff */
List<SomeKey> keysCopy = new ArrayList<SomeKey>();
synchronized (internalMap) {
keysCopy.addAll(internalMap.keySet());
}
/*
do stuff with keysCopy, update a temporary map
*/
synchronized (internalMap) {
internalMap.putAll(tempMap);
}
}
Сохранить доступ к internalMap syncronized , в противном случае возникает исключение java.util.ConcurrentModificationException, потому что HashMap # modCount (который записывает структурные изменения) может быть изменен одновременно во время итерации набора ключей (из-за keysCopy. addAll (вызов internalMap.keySet ()).
LinkedHashMap javaDoc указывает: «В связанных хэш-картах с упорядоченным доступом простой запрос карты с помощью get является структурной модификацией.»