提问者:小点点

Java并发:当并发线程只删除元素时,HashMap Vs并发HashMap


我有一个主线程,它创建一个HashMap,向其中添加多个可运行对象,然后启动每个runnable(将HashMap传递给每个)。runnable在即将完成处理之前从映射中删除其对象。

我想知道在这种情况下是否有任何理由使用并发哈希图(而不是哈希图)——可运行对象在地图上执行的唯一操作是从地图中删除自己。在这种情况下,是否有并发考虑需要使用并发哈希图?

private final Map<Integer, Consumer> runnableMap = new HashMap<>();

Runnable runnable;

for (int i = 1; i <= NUM_RUNNABLES; i++) {
    runnable = new Consumer(i, runnableMap);
    runnableMap.put(i, runnable);
    executionContext.execute(runnable);
}
private final Integer consumerNumber;
private final Map<Integer, Consumer> runnableMap;

public Consumer(int consumerNumber, final Map<Integer, Consumer> runnableMap){
    this.consumerNumber = consumerNumber;
    this.runnableMap = runnableMap;
}

public void run() {
    :::
    // business logic
    :::
    // Below remove is the only operation this thread executes on the map
    runnableMap.remove(consumerNumber);
}

共3个答案

匿名用户

如果您这样做的原因是跟踪线程完成,为什么不使用CountdownLatch?不确定HashMap是否仅在删除时才会出现并发问题,我建议仅在您的代码不会在任何可能的问题上中断时使用它,或者使用并发HashMap。

匿名用户

HashMap的javadoc说:

请注意,此实现不是同步的。

如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了映射,则必须在外部同步。(结构修改是任何添加或删除一个或多个映射的操作;仅仅更改与实例已经包含的键关联的值不是结构修改。)这通常是通过在自然封装映射的某个对象上进行同步来实现的。

如上所述,删除是一种结构更改,您必须使用同步。

此外,在Hashmap的RemoveNode()方法(由delete()方法调用)中,modCount变量递增,它负责ContranstModificationException。因此,如果您在不同步的情况下删除元素,您可能会遇到此异常。

因此,您必须使用ConCurrentHashMap

匿名用户

您询问了HashMapConCurrentHashMap之间的差异,但是还有一个额外的数据结构需要考虑:Hashtable。每个都有差异和权衡。您需要评估哪个最适合您的预期用法。

>

  • HashMap是未同步的,因此如果多个线程可以读取或写入它,您的结果将是不可预测的。HashMap还允许null作为键或值。

    Hashtable是同步的,不支持空键或值。来自Hashtable Javadoc:

    哈希表是同步的。如果不需要线程安全的实现,建议使用HashMap代替Hashtable。如果需要一个线程安全的高并发实现,那么建议使用并发HashMap代替Hashtable。

    并发HashMap是线程安全的,不允许将null用作键或值。