2010-10-19 50 views
0

在下面的代碼片段中,爲什麼需要返回數據[i]的副本。如果不進行復制,多線程環境中究竟發生了什麼。Java:返回對象的副本

protected Object[] data; 
.. 
public synchronized Object get(int i) 
throws NoSuchElementException 
{ if (i < 0 || i >= size) 
     throw new NoSuchElementException(); 
    return data[i]; 
} 

回答

4

爲什麼它希望返回數據[I]的副本。

你在指數i返回參考副本,而不是一個對象的副本。

除非通過例如data[i].clone()創建對象的副本,否則您將始終擁有一個對象並在線程中共享對它的引用。在多個線程中共享對單個對象的引用沒有任何問題。

如果沒有進行復制,多線程環境中究竟發生了什麼。

好吧,除非你使用的同步方法同步線程,等待/通知或java.util.concurrent - 班你可能最終與race-conditions。競爭條件基本上是執行結果依賴於特定調度(線程可以執行的順序)的情況。

如果您在線程中共享某個類的對象,則應將其設計爲"thread safe"。如果您的對象代表value object,我建議您將它製作爲immutable

+0

爲什麼需要它? – devnull 2010-10-19 06:36:06

+2

@iJeeves如果你不需要它,它是不需要的。看到我的答案。 – 2010-10-19 06:37:19

2

嗯,我沒有看到這個方法沒有錯,因爲它是 - 它沒有複製。這取決於你打算如何處理返回的對象。如果您將從不同的線程修改它,那麼爲每個線程返回一個副本是一個好主意。

1

由於該方法是同步的,並且除非同一個包中的其他人不處理數據數組,否則應該沒有多線程問題。

1

因爲它可能更舒適的調用代碼。如果你沒有返回一個副本(如你的例子所示),如果你想避免競爭條件,你必須在返回的引用(data [i])上同步。

1

希望返回[I]

因爲你的get()是同步的,很可能多個線程訪問將並行數據對象的副本。現在,這將導致問題,如果以下幾點爲真

  • 存儲在數組中的對象是muteable(可改變狀態)
  • 對象的方法不同步(該對象不是線程)

如果這些是真的,如果兩個線程同時處理對象,最終可能會導致對象處於無效狀態。創建對象的副本可以防止這種情況發生,因爲每個線程都會處理它自己的副本。

0

由於多個線程可以直接訪問同一個對象,因此您可能會遇到意外行爲的問題。

考慮以下幾點:

線程A:

Object foo = get(1); 
foo.member += 5; 

線程B:

Object bar = get(1); 
bar.member = 2; 

假設這2個線程同時運行時,你無法知道什麼樣的最終狀態的方式存儲在數據[1]中的對象將是。線程切換控制點是不可預測的,雖然99%的時間可以正常工作,但您的代碼可能會出現間歇性錯誤。

你真正想要做的是保護任何修改對象數據[]與「同步」關鍵詞的狀態的方法。吸氣劑,吸附劑等應全部同步。有一個同步的方法,只是實現對象的引用是毫無意義的。

0

請不要使用克隆來創建副本,它有它自己的錯誤。使用複製構造函數或創建一個新對象並設置成員值並返回相同的值。