2011-03-31 113 views
2

我想迭代一個java List,使用舊的方式for(int i ...)循環,因爲對於給定的i和循環迭代,我想訪問多個相對於i的元素。然後我不能使用(Object o:objects)列表迭代器。關於java同步的簡單問題

我該如何確保在執行它時沒有其他代碼可以訪問列表?

我試圖

synchronized(path.getPoints()){ 
    for (int i = 0; i < path.getPoints().size(); i++){ 
     ... 
    } 
} 

其中路徑對象容納的列表,並且還

synchronized(path){ 
    for (int i = 0; i < path.getPoints().size(); i++){ 
     ... 
    } 
} 

synchronized(this){ 
    for (int i = 0; i < path.getPoints().size(); i++){ 
     ... 
    } 
} 

其中 「這」 是想渲染器在沒有同步問題的情況下退出路徑。

由於提前,

馬丁

+0

您發佈的同步代碼應該適用於所有三種情況。你確定你沒有其他線程訪問同步守衛之外的路徑嗎? – templatetypedef 2011-03-31 09:44:39

+0

是什麼讓你認爲另一個線程正在訪問列表? – 3urdoch 2011-03-31 09:47:12

+0

@murdoch:我有一個編輯器線程在後臺運行,一個UI線程連續運行並呈現點列表。 @template:我只同步這兩個線程中的一個,而不是兩個 – Martin 2011-04-01 10:31:03

回答

7

如何確保其他代碼 可以訪問列表,而我 執行它?

通過確保所有其他代碼同步同一個對象。 synchronized(path.getPoints())是最好的選擇。 getPoints()可能是一個好主意,可以通過Collections.synchronizedList()返回包裝列表 - 然後您不需要明確同步簡單的get()add()調用,但仍需要迭代的同步。

複雜嗎?是啊。這就是共享內存多線程編程被認爲非常困難的原因。

+0

我認爲在這個特定的問題中,使用synchronizedList是無用的,因爲您必須使用同一個同步對象來同步所有獲取,添加和迭代。看到我的回答... – nanda 2011-03-31 10:04:25

+0

@nanda:實際上,這種情況被正確描述爲正確使用API​​文檔中synchronizedList()的示例。顯然,包裝器使用它自己進行同步,以便允許外部同步工作。 – 2011-03-31 10:12:50

+0

你是對的... – nanda 2011-03-31 10:16:49

0

你可以做path.getPoints()同步,並返回點列表(或者數組)的副本。然後在迭代它時不需要同步。如果點是私密的,你可以很容易地確保Path中訪問它的所有方法也是同步的。

0

「synchronized(this)」(其中「this」是您的渲染器)確保沒有其他線程可以同時運行相同的渲染器;但是其他線程可以訪問列表和「路徑」對象。

0

你最好去做的事情可能是確保任何使用集合(path.getPoints())寫入的東西在同步塊中(在同一個集合上)這樣做,以便消費者(例如只讀)的希望使用枚舉器的集合可以通過在集合上使用同步塊來安全地執行此操作。

0

我建議你這樣寫。

List<Point> points = path.getPoints() 
synchronized(points){ 
    for (Point point: points){ 
     ... 
    } 
} 

這確保getPoints()不會返回不同的東西並簡化代碼恕我直言。

我也將使用@Michaels的建議,無論是同步每次getPoints()被訪問或進行一次一Collectons.synchronizedList()或線程安全的名單像 的CopyOnWriteArrayList()

注:如果您使用一個線程安全列表,你可能不需要同步它。