2011-03-13 69 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