Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 迭代过程中的HashMap插入_Java_Multithreading_Events_Collections - Fatal编程技术网

Java 迭代过程中的HashMap插入

Java 迭代过程中的HashMap插入,java,multithreading,events,collections,Java,Multithreading,Events,Collections,我在映射中维护可变数量的事件侦听器: private final Map<String, EventListener> eventListeners = new ConcurrentHashMap<>(); 每次发生事件时,我都会迭代所有侦听器并激发它们: eventListeners.forEach((name, listener) -> { listener.handle(event); }); 该环境是单线程的,有趣的是事件侦听器实现可能会在触发时

我在映射中维护可变数量的事件侦听器:

private final Map<String, EventListener> eventListeners = new ConcurrentHashMap<>();
每次发生事件时,我都会迭代所有侦听器并激发它们:

eventListeners.forEach((name, listener) -> {
    listener.handle(event);
});
该环境是单线程的,有趣的是事件侦听器实现可能会在触发时插入另一个事件侦听器

对于“普通”HashMap,这显然会导致
ConcurrentModificationException
,这就是我使用
ConcurrentHashMap
的原因

我看到的情况是,由另一个事件侦听器插入的事件侦听器可能会被同一个事件触发,因为它是在迭代过程中插入的,我认为这是
ConcurrentHashMap
的预期行为

然而,我不希望发生这种情况,所以我想推迟事件侦听器的任何插入,直到对所有侦听器的迭代完成

因此,我引入了一个
线程
,它在使用
倒计时闩锁插入侦听器之前等待迭代完成:

public void addEventListener(final String name, final EventListener listener) {
    new Thread(() -> {
        try {
            latch.await();
        } catch (InterruptedException e) {}
        eventListeners.put(name, listener);
    }).start();
}
以及对所有侦听器的迭代:

latch = new CountDownLatch(1);
eventListeners.forEach((name, listener) -> {
    listener.handle(event);
});
latch.countDown();

它按预期工作,但我想知道这是否是一个很好的解决方案,是否有更优雅的方法来实现我的需求。

我还没有完全分析您的问题,但通常的方法是使用
CopyOnWriteArraYList

public class CopyOnWrite {
   private CopyOnWriteArrayList<ActionListener> list = 
           new CopyOnWriteArrayList<>();

   public void fireListeners() {
      for( ActionListener el : list ) 
         el.actionPerformed( new ActionEvent( this, 0, "Hi" ) );
   }

   public void addListener( ActionListener al ) {
      list.add( al );
   }
}
公共类CopyOnWrite{
私有CopyOnWriteArrayList

CopyOnWriteArrayList是由 写时复制数组。此实现与 CopyOnWriteArraySet。无需同步,即使在 迭代,并保证迭代器永远不会抛出 ConcurrentModificationException。此实现非常适合于 维护不经常更改的事件处理程序列表,以及 遍历非常频繁,而且可能非常耗时


我还没有完全分析您的问题,但通常的方法是使用
CopyOnWriteArraYList

public class CopyOnWrite {
   private CopyOnWriteArrayList<ActionListener> list = 
           new CopyOnWriteArrayList<>();

   public void fireListeners() {
      for( ActionListener el : list ) 
         el.actionPerformed( new ActionEvent( this, 0, "Hi" ) );
   }

   public void addListener( ActionListener al ) {
      list.add( al );
   }
}
公共类CopyOnWrite{
私有CopyOnWriteArrayList

CopyOnWriteArrayList是由 写时复制数组。此实现与 CopyOnWriteArraySet。无需同步,即使在 迭代,并保证迭代器永远不会抛出 ConcurrentModificationException。此实现非常适合于 维护不经常更改的事件处理程序列表,以及 遍历非常频繁,而且可能非常耗时


我还没有完全分析您的问题,但通常的方法是使用
CopyOnWriteArraYList

public class CopyOnWrite {
   private CopyOnWriteArrayList<ActionListener> list = 
           new CopyOnWriteArrayList<>();

   public void fireListeners() {
      for( ActionListener el : list ) 
         el.actionPerformed( new ActionEvent( this, 0, "Hi" ) );
   }

   public void addListener( ActionListener al ) {
      list.add( al );
   }
}
公共类CopyOnWrite{
私有CopyOnWriteArrayList

CopyOnWriteArrayList是由 写时复制数组。此实现与 CopyOnWriteArraySet。无需同步,即使在 迭代,并保证迭代器永远不会抛出 ConcurrentModificationException。此实现非常适合于 维护不经常更改的事件处理程序列表,以及 遍历非常频繁,而且可能非常耗时


我还没有完全分析您的问题,但通常的方法是使用
CopyOnWriteArraYList

public class CopyOnWrite {
   private CopyOnWriteArrayList<ActionListener> list = 
           new CopyOnWriteArrayList<>();

   public void fireListeners() {
      for( ActionListener el : list ) 
         el.actionPerformed( new ActionEvent( this, 0, "Hi" ) );
   }

   public void addListener( ActionListener al ) {
      list.add( al );
   }
}
公共类CopyOnWrite{
私有CopyOnWriteArrayList

CopyOnWriteArrayList是由 写时复制数组。此实现与 CopyOnWriteArraySet。无需同步,即使在 迭代,并保证迭代器永远不会抛出 ConcurrentModificationException。此实现非常适合于 维护不经常更改的事件处理程序列表,以及 遍历非常频繁,而且可能非常耗时


如果您的解决方案允许您实现
线程
,则可能出现问题

您可以避免在原始地图上迭代,而在其副本上迭代

比如:

Map<String, EventListener> eventListenerCopy = new HashMap<>(eventListeners);
eventListenerCopy.forEach((name, listener) -> {
  listener.handle(event);
});
Map eventListenerCopy=newhashmap(eventListeners);
eventListenerCopy.forEach((名称,侦听器)->{
句柄(事件);
});
因此,如果您的
句柄
事件将添加新事件,则副本将无法看到它,而副本将迭代所有原始事件


或者,如果强制某个特定方法添加新的侦听器,则可以创建一个临时列表,保存所有新的侦听器,并在迭代完成时检查此新列表,如果存在,则将新的侦听器放在原始列表中(如果不希望每次都创建映射的副本,则更好).

如果您的解决方案允许您实现
线程
,则可能出现问题

您可以避免在原始地图上迭代,而在其副本上迭代

比如:

Map<String, EventListener> eventListenerCopy = new HashMap<>(eventListeners);
eventListenerCopy.forEach((name, listener) -> {
  listener.handle(event);
});
Map eventListenerCopy=newhashmap(eventListeners);
eventListenerCopy.forEach((名称,侦听器)->{
句柄(事件);
});
因此,如果您的
句柄
事件将添加新事件,则副本将无法看到它,而副本将迭代所有原始事件


或者,如果强制某个特定方法添加新的侦听器,则可以创建一个临时列表,保存所有新的侦听器,并在迭代完成时检查此新列表,如果存在,则将新的侦听器放在原始列表中(如果不希望每次都创建映射的副本,则更好).

如果您的解决方案允许您实现
线程
,则可能出现问题

您可以避免在原始地图上迭代,而在其副本上迭代

比如:

Map<String, EventListener> eventListenerCopy = new HashMap<>(eventListeners);
eventListenerCopy.forEach((name, listener) -> {
  listener.handle(event);
});
Map eventListenerCopy=newhashmap(eventListeners);
eventListenerCopy.forEach((名称,侦听器)->{
句柄(事件);
});
因此,如果您的
句柄
事件将添加新事件,则副本将无法看到它,而副本将迭代所有原始事件

或者,如果强制指定