2011-03-13 30 views
0

我有我的代码:遍历静态套装 - java的

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中的数据。

因此,我定义了一个singleton类(通过spring bean),它持有我需要处理的数据集(数据是数字),并且每次修改Set时我都有Web服务Call A.一旦用户请求Web服务调用B - 我必须收集迄今为止的数据并执行一些操作。

回答

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

记得同时调用add()'。 – Boris 2011-03-13 08:29:38

+0

所以我仍然需要设置workItemsForTasks = Collections.synchronizedSet(new HashSet());到集合? – Dejell 2011-03-13 11:30:11

+0

@Odelya,是的,你应该。使用'Collections.synchronizedSet()'加上面的是线程安全的。这不是唯一的解决方案,但它很简单。 – rlibby 2011-03-13 11:39:01

2

静态状态通常是一件坏事。每次你看到它的时候,警惕

此代码将在多线程环境中执行,所以你所写的内容将无法正常工作 - 你会得到ConcurrentModificationException

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

你不是在跟随“tell dont ask”,并且特别违反LoD-F(http://pragprog.com/articles/tell-dont-ask) - 这是一种说法,很快就会出现yur代码的困难跟随谁做什么。

或者,为了破解大部分工作的内容,请使用CopyOnWriteArraySet

+0

谢谢。我编辑了我的问题。你能请建议一个更好的设计? – Dejell 2011-03-13 09:36:49

+1

那么,简单地说,你有一个“模型” - 这是一些需要完成的工作。那么你有两件事情发生。有人在事情列表中增加了一件事,另一件事是有人要求完成工作,并且结果被查看了?无论如何,你确实需要共享状态 - 但你需要让它线程安全。 StuffThatNeedsToBeDone然后需要一些方法来添加工作(Work w),以及一些方法来做Work()。如果工作是同步完成的,那么你可以只用Iterable doWork(),然后以某种方式渲染回用户。所有同步都隐藏起来... – time4tea 2011-03-13 10:20:50

1

首先,假设你说地图的时候,你的意思是Set。按照Java Doc

请注意,此实现不同步。如果多个线程 同时访问散列集,并且至少一个线程修改了该集,则它必须在外部同步。这通常是通过同步某些自然封装该集合的对象来实现的。如果不存在这样的对象,则该集应该使用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 
} 
+0

谢谢。我编辑了我的问题。你能请建议一个更好的设计? – Dejell 2011-03-13 09:37:22