Форум администраторов игровых серверов

Форум администраторов игровых серверов (https://forum.zone-game.info/TT.php)
-   Работа со скриптами (https://forum.zone-game.info/forumdisplay.php?f=37)
-   -   LinkedHashMap в эффекте (https://forum.zone-game.info/showthread.php?t=41881)

finfan 25.12.2016 01:03

LinkedHashMap в эффекте
 
При onStart() эффекта, в LinkedHashMap добавляет ключ-значение.
При onExit() эффекта, ключ-значение оттуда удаляется.

Словлю ли я Exception?, если onStart() по времени, вызовется одновременно с onExit() и карта, попробует добавить и удалить ключ-значение? Что вообще здесь происходит?

Может стоит использовать в таких случаях ConcurrentHashMap?

Mangol 25.12.2016 02:48

Re: LinkedHashMap в эффекте
 
ConcurrentModificationException можно словить лишь в том случае, если во время перебора forEach, Iterator, удалить, добавить, либо еще сделать какую либо операцию по изменению элементов. Она приведет к ошибке.

P.S. Зачем нужна именно эта мапа ?) Для более ясного ответа, нужно знать - мапа работает на 1-го игрока, либо глобально на эффект ?

finfan 25.12.2016 04:01

Re: LinkedHashMap в эффекте
 
Цитата:

Сообщение от Mangol (Сообщение 422166)
ConcurrentModificationException можно словить лишь в том случае, если во время перебора forEach, Iterator, удалить, добавить, либо еще сделать какую либо операцию по изменению элементов. Она приведет к ошибке.

P.S. Зачем нужна именно эта мапа ?) Для более ясного ответа, нужно знать - мапа работает на 1-го игрока, либо глобально на эффект ?

Мапа работает на одного игрока (один игрок управляет своей мапой) и содержит в себе данные на других (на ком лежит эффект). Накладывая эффект на очередную жертву, мапа обновляется и удаляется в зависимости от максимального окл-ва наложений эффекта:
Например, если эффект можно наложить лишь на 3 цели - одним кастером. При наложении на 4-ую, из мапы убирается 1 товарищ (и эффект с него тоже снимается) и добавляется другой.

Anikey 25.12.2016 08:42

Re: LinkedHashMap в эффекте
 
Цитата:

Сообщение от finfan (Сообщение 422163)
Словлю ли я Exception?, если onStart() по времени, вызовется одновременно с onExit() и карта, попробует добавить и удалить ключ-значение? Что вообще здесь происходит?

Нет, не словишь.
Если нечего удалять вернет null, как и в случае putIfAbsent, etc...
Как подметил Mangol ConcurrentModificationException - мы можем выхватить, только если удаляем напрямую из коллекции - во время работы итератора. Нужно использовать метод итератора remove(), чтобы было корректно.

Mangol 25.12.2016 11:22

Re: LinkedHashMap в эффекте
 
Цитата:

Сообщение от Anikey (Сообщение 422170)
Нет, не словишь.
Если нечего удалять вернет null, как и в случае putIfAbsent, etc...
Как подметил Mangol ConcurrentModificationException - мы можем выхватить, только если удаляем напрямую из коллекции - во время работы итератора. Нужно использовать метод итератора remove(), чтобы было корректно.

remove(); Итератора не спасет, все равно получим ConcurrentModificationException.
П.1 Не только удаляем, при любом добавлении либо удалении, получим ConcurrentModificationException.
На сколько я помню там есть проверка.
int mod=correctMod;
if(mod != correctMod)
привет ConcurrentModificationException;

Добавлено через 10 минут
Цитата:

Сообщение от finfan (Сообщение 422167)
Мапа работает на одного игрока (один игрок управляет своей мапой) и содержит в себе данные на других (на ком лежит эффект). Накладывая эффект на очередную жертву, мапа обновляется и удаляется в зависимости от максимального окл-ва наложений эффекта:
Например, если эффект можно наложить лишь на 3 цели - одним кастером. При наложении на 4-ую, из мапы убирается 1 товарищ (и эффект с него тоже снимается) и добавляется другой.

А вообще.... Если боишься что влетит 2 потока, и что то не правильно добавится - удалиться. Используй ConcurrentHashMap<>();

Ну если на крайний случай map = HashMap<>();
//write code;
synchronized(map) // mutex
{
//write code;
}
//write code;

Hack 25.12.2016 12:18

Re: LinkedHashMap в эффекте
 
Если мапка не используется в каких либо итераторах, то можешь смело добавлять и тереть в ней сколько влезет.
Если же задействована в итераторе (не важно по ключам, значениям или парам), тогда уже нужен пакет concurency, либо синхронизация.
Вообще любое изменяемое хранилище, к которому могут получить доступ несколько потоков по дефолту должно быть конкурентным.

Anikey 25.12.2016 12:19

Re: LinkedHashMap в эффекте
 
Mangol,
PHP код:

final LinkedHashMap<ObjectObjectlinked = new LinkedHashMap<>();
linked.put("1""1");
linked.put("2""2");
linked.put("3""3"); 

Следующие выражения выбьют ошибку:
Java 8:
PHP код:

linked.entrySet().stream().filter((i) -> ("3".equals(i.getKey()))).forEachOrdered((i) -> {
     
linked.remove(i.getKey());
}); 

Ниже 8 версии:
PHP код:

for (Entry<ObjectObjectlinked.entrySet()) {
    if (
"3".equals(i.getKey())) {
         
linked.remove(i.getKey());
    }


А вот это решение отработает правильно и без ошибок:
PHP код:

final Iterator<Entry<ObjectObject>> linked.entrySet().iterator();
while (
i.hasNext()) {
    if (
"3".equals(i.next().getKey())) {
       
i.remove();
    }



Mangol 25.12.2016 12:29

Re: LinkedHashMap в эффекте
 
Цитата:

Сообщение от Anikey (Сообщение 422175)
Mangol,
PHP код:

final LinkedHashMap<ObjectObjectlinked = new LinkedHashMap<>();
linked.put("1""1");
linked.put("2""2");
linked.put("3""3"); 

Следующие выражения выбьют ошибку:
Java 8:
PHP код:

linked.entrySet().stream().filter((i) -> ("3".equals(i.getKey()))).forEachOrdered((i) -> {
     
linked.remove(i.getKey());
}); 

Ниже 8 версии:
PHP код:

for (Entry<ObjectObjectlinked.entrySet()) {
    if (
"3".equals(i.getKey())) {
         
linked.remove(i.getKey());
    }


А вот это решение отработает правильно и без ошибок:
PHP код:

[COLOR="red"]final Iterator<Entry<ObjectObject>> linked.entrySet().iterator();
while (
i.hasNext()) {
    if (
"3".equals(i.next().getKey())) {
       
i.remove();
    }
}[/
COLOR


if ("2".equals(i.next().getKey())) {
i.remove();
}

Сделай 2-ое удаление :redlol:

Anikey 25.12.2016 12:36

Re: LinkedHashMap в эффекте
 
Цитата:

Сообщение от Mangol (Сообщение 422176)
Сделай 2-ое удаление

Даже в разном порядке:
PHP код:

final Iterator<Entry<ObjectObject>> linked.entrySet().iterator();
    while (
i.hasNext()) {
       switch((String)
i.next().getKey()) {
           case 
"2":
           case 
"1":
               
i.remove();
               break;
     }



Mangol 25.12.2016 12:54

Re: LinkedHashMap в эффекте
 
Цитата:

Сообщение от Anikey (Сообщение 422177)
Даже в разном порядке:
PHP код:

final Iterator<Entry<ObjectObject>> linked.entrySet().iterator();
    while (
i.hasNext()) {
       switch((String)
i.next().getKey()) {
           case 
"2":
           case 
"1":
               
i.remove();
               break;
     }



PHP код:

        public final boolean remove(Object o) {
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
                Object key = e.getKey();
                Object value = e.getValue();
                return removeNode(hash(key), key, value, true, true) != null;
            }
            return false;
        }

Код из явки действительно поддерживает это. :)

Но есть побочные эффекты, такие как
PHP код:

    public Set<Map.Entry<K,V>> entrySet() {
       
Set<Map.Entry<K,V>> es;
        return (
es entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
    }

    final class 
LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
        public final 
int size()                 { return size; }
        public final 
void clear()               { LinkedHashMap.this.clear(); }
        public final 
Iterator<Map.Entry<K,V>> iterator() {
            return new 
LinkedEntryIterator();
        }
    final class 
LinkedEntryIterator extends LinkedHashIterator
        
implements Iterator<Map.Entry<K,V>> {
        public final 
Map.Entry<K,Vnext() { return nextNode(); }
    } 




PHP код:

        final LinkedHashMap.Entry<K,VnextNode() {
            
LinkedHashMap.Entry<K,Vnext;
            if (
modCount != expectedModCount)
                throw new 
ConcurrentModificationException();
            if (
== null)
                throw new 
NoSuchElementException();
            
current e;
            
next e.after;
            return 
e;
        } 



Если в хранилище залетело какой то объект во время

while (i.hasNext()) {

switch((String)i.next().getKey()) {


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


Текущее время: 13:38. Часовой пояс GMT +3.

Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot