0

Я держу карту объектов, и каждый раз, когда объект добавляется к ней, все остальные объекты на карте должны быть уведомлены о новом объекте и наоборот. Эти объекты запускаются сами по себе: thread процесс (каждый из них запущен с main) может вызывать метод, который добавляет их на карту, чтобы объект мог быть добавлен во время итерации, вызванной добавлением предыдущего объекта.Как перебирать карту при одновременном добавлении к ней значений?

Это пример кода, который у меня есть. Вот объекты, о которых я говорил выше

class Notifier { 

    String name; 
    Hub hub; 

    Notifier(String name) { 

     this.name = name; 
     hub.add(this); 
    } 

    void acknowledge(String name) { 

     System.out.println(this.name + " was notified of " + name); 
    } 
} 

Вот это вещь, которая держит карту

public class Hub { 

    ConcurrentMap<String, Notifier> map = new ConcurrentHashMap<>(); 

    void add(Notifier notifier) { 

     map.putIfAbsent(notifier.name, notifier); 

     Iterator<Entry<String, Notifier>> it = map.entrySet().iterator(); 
     while (it.hasNext()) { 
      Entry<String, Notifier> entry = it.next(); 
      if (!entry.getKey().equals(notifier.name)) { 
       entry.getValue().acknowledge(notifier.name); 
       notifier.acknowledge(entry.getKey()); 
      } 
     } 
    } 
} 

Я попытался ConcurrentHashMap, но это не должно быть так. Моя проблема в том, что результаты, которые я получаю, каждый объект уведомляется не один раз о другом , если я запускаю свои потоки вместе. Я получаю

notifier1 был уведомлен о notifier2
notifier1 был уведомлен о notifier2
notifier1 был уведомлен о notifier3
notifier1 был уведомлен о notifier3
notifier1 был уведомлен о notifier4
notifier1 был уведомлен о notifier4

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

notifier1 был уведомлен о notifier2
notifier1 был уведомлен о notifier3
notifier1 был уведомлен о notifier4

и аналогичные для других.

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

Как сделать так, чтобы каждый объект был уведомлен ровно 1 раз из всех остальных? Может быть, эта параллельная карта не хороша, и мне нужно что-то синхронизировать? Меня не волнует порядок дополнений.

+0

Что это за объекты? Есть ли веская причина сделать их независимыми потоками, а не использовать обратный подход? – chrylis

+0

@chrylis это как клиенты и сервер. Каждый клиент, который приходит, уведомляется обо всех других клиентах, и они уведомляются об этом. не является ли это своего рода обратным вызовом уже потому, что хаб вызывает методы на объекте-уведомлении? извините, если я не понимаю. – Mark

+0

Сортировка, но вы специально сказали, что они «работают на своих потоках», что не соответствует коду, который вы разместили здесь. – chrylis

ответ

0

Я думаю, что ошибка довольно проста. Вы не отменяете уведомление в случае дубликата уведомления.

public class Hub { 

    ConcurrentMap<String, Notifier> map = new ConcurrentHashMap<>(); 

    void add(Notifier notifier) { 

     if (map.putIfAbsent(notifier.name, notifier) == null) { 

      Iterator<Entry<String, Notifier>> it = map.entrySet().iterator(); 
      while (it.hasNext()) { 
       Entry<String, Notifier> entry = it.next(); 
       if (!entry.getKey().equals(notifier.name)) { 
        entry.getValue().acknowledge(notifier.name); 
        notifier.acknowledge(entry.getKey()); 
       } 
      } 
     } 
    } 
} 
+0

Но не существует нескольких запусков одного и того же уведомителя - каждый раз вызывает метод add один раз. Я обновлю свой код, кажется, что я нахожусь на более глубокой воде, чем я думал изначально. – Mark

+0

Если у вас есть несколько из них с тем же именем, например. тот же ключ, тогда карта предотвращает дубликаты, но уведомления отправляются в любом случае. – Max

+0

У меня нет нескольких имен с таким же именем. Конструктору присваивается уникальное имя. – Mark