循环遍历静态Set-java

时间:2011-03-13 07:03:16

标签: java multithreading spring hashset

我的代码中有:

public static Set<Long> workItemsForTasks = new HashSet<Long>();

这是一个Web应用程序,在代码中,用户可以向地图添加新项目 - 我添加如下代码:

WorkflowOperations.workItemsForTasks.add(workItem.getId());

一旦工作流程到达特定代码,我就像这样遍历地图:

 Iterator workItemsIter = service.workItemsForTasksToBMS.iterator();
   while (workItemsIter.hasNext()) {
workItemsIter.remove();

    ...
    }

我的问题是:

一旦我得到迭代器 - 如果另一个用户向地图添加了一个新项目(因为它不在同一个网页中) - 它会在我循环时影响地图吗?或者检索迭代器可以确保它保持地图大小直到循环开始的时间?

EDITED

这是一个接受不同Web服务调用的Web应用程序。

在呼叫A中,用户可能会添加呼叫B中需要处理的数据。

所以我定义了一个单例类(通过spring bean),它保存了我需要处理的数据集(数据是数字),每次我有Web服务时都会修改Set。一旦用户询问对于Web服务调用B - 我必须收集到目前为止的数据并用它执行一些操作。

3 个答案:

答案 0 :(得分:3)

是否从多个线程同时访问该组?

如果这一切都发生在一个线程上,那么你正在做的事情很好。

但是,如果有并发访问,那么你做错了两件事。首先,HashSet不是线程安全的。其次,在迭代它时修改HashSet(通过Iterator除外)是错误的,并且(希望!)会产生ConcurrentModificationException

您可以通过考虑java.util.concurrent中的课程来解决这个问题,或者您也可以在案例中添加一些自己的同步。您可以同步对集合的访问,当您需要从中删除内容时,请立即执行所有操作。

private static void doMyStuff() {
    Set<Long> myWorkingSet;
    synchronized (workItemsForTasks) {
        myWorkingSet = new HashSet(workItemsForTasks);
        workItemsForTasks.clear();
    }
    for (long x : myWorkingSet) {
        // do something
    }
}

如果您执行此类操作,则应在类中隐藏workItemsForTasks隐藏访问方法,以确保正确同步。

答案 1 :(得分:2)

静态通常是一件坏事。每当你看到它时,要小心

此代码将在多线程环境中执行,因此您所编写的内容将无效 - 您将获得ConcurrentModificationException

你没有域名模型!多组多头没有意义。尝试用更高层次的抽象来表达正在发生的事情。

你没有关注“告诉不要问”,特别是违反了LoD-F(http://pragprog.com/articles/tell-dont-ask) - 这是一种说明你的代码很快就会很难的方式跟随谁做了什么。

或者,要破解大部分工作的东西,请使用CopyOnWriteArraySet

答案 2 :(得分:1)

首先,我假设您说地图时,实际上是Set。根据{{​​3}},

  

请注意,此实现未同步。如果有多个线程   同时访问哈希集,以及至少一个线程   修改集合,必须在外部同步。这是   通常通过自然地同步某个对象来完成   封装集合。如果不存在这样的对象,则该集合应该是   使用Collections.synchronizedSet方法“包装”。这是最好的   在创建时完成,以防止意外的不同步访问   集:

HashSet的线程安全实现如下:

Set s = Collections.synchronizedSet(new HashSet(...));

就迭代器而言,在存在不同步的并发修改时不可能做出任何硬保证,因此在迭代时应该手动同步返回的集合,否则结果将是不确定的。

Set workItemsForTasks = Collections.synchronizedSet(new HashSet());
synchronized(workItemsForTasks) {
Iterator workItemsIter  = workItemsForTasks.iterator(); //Must be in synchronized block
while (workItemsIter.hasNext())
    //Do Something
}