2012-02-23 38 views
7

Nếu tôi có một bộ sưu tập đồng bộ như thế nàyđược đồng bộ hóa với phương thức toArray() của Collection?

Collection c = Collections.synchronizedCollection(myCollection);

javadoc cho synchronizedCollection mentiones rằng lặp bên ngoài phải được đồng bộ như thế này:

synchronized (c) { 
Iterator i = c.iterator(); 
while (i.hasNext()) { 
    process (i.next()); 
} 
} 

Tôi có thể giả thiết rằng c.toArray() được đồng bộ hóa và do đó không thay đổi cho bộ sưu tập sẽ xảy ra khi phương thức thực thi?

Hoặc tôi cần phải đồng bộ hóa nó là tốt:

synchronized (c) { 
    c.toArray(); 
} 
+0

'CollectionUtils' ở đâu? Đó không phải là một lớp Java API chuẩn. – Jesper

+0

Tôi cho rằng anh ta có nghĩa là 'java.util.Collections', không phải' CollectionUtils'. – skaffman

+0

Đó là lớp tiện ích của Apache Commons Collections ' –

Trả lời

5

Từ Javadoc cho synchronizedCollection:

Trả về một đồng bộ bộ sưu tập (thread-safe) được hỗ trợ bởi bộ sưu tập xác định.

Do đó, c.toArray() không yêu cầu bất kỳ đồng bộ hóa bổ sung nào. Phương pháp toArray() của SynchronizedCollection sẽ thực hiện khóa cho bạn. Về bản chất, đó là toàn bộ quan điểm của synchronizedCollection().

Nếu bạn muốn xác nhận rằng việc đọc hợp đồng này đồng ý với việc triển khai thực tế, hãy xem GrepCode.

+0

Cảm ơn điều đó khá nhiều đã nói lên tất cả. Và GrepCode thật tuyệt vời! – artur

+0

Hoàn toàn không chính xác. Bạn KHÔNG THỂ và KHÔNG NÊN dựa vào việc thực hiện mã. Bạn PHẢI dựa vào hợp đồng được cung cấp, và vì dường như không phải là một hợp đồng được cung cấp, bạn KHÔNG THỂ giả sử nó được đồng bộ hóa. – Woot4Moo

+0

@ Woot4Moo Các javadocs 'đồng bộ * 'phương thức' khá chung chung - điều đó có nghĩa là chúng ta không bao giờ nên sử dụng chúng? Tất cả nó thực sự nói rằng đó là thread-an toàn, nhưng tôi nghĩ rằng nó an toàn để giả định rằng điều này có nghĩa là * tất cả * phương pháp của nó là thread-an toàn. Cảnh báo/ví dụ về các trình vòng lặp cũng ngụ ý rằng sự an toàn luồng xuất phát từ việc đồng bộ hóa trên đối tượng được trả về. – yshavit

2

Nếu bạn đang nói về tiện ích thu thập dữ liệu commons của Apache, câu trả lời là có. CollectionUtils.synchronizedCollection(...) lợi nhuận một thể hiện của SynchronizedCollection ai toArray() phương pháp là:

public Object[] toArray() { 
     synchronized (lock) { 
      return collection.toArray(); 
     } 
    } 
+0

Cảm ơn. Tôi thực sự có nghĩa là lớp 'java.util.Collections' chuẩn. Nhưng tôi có thể thấy rằng asnwer là như nhau cho cả hai. – artur

1

Bạn không cần nó, phương pháp thực hiện đồng bộ hóa cho bạn.

0

Nếu bạn đang sử dụng java.util.Collections là một phần của API thu thập Java chuẩn, thì tất cả các phương thức trên SynchronizedCollection được trả về được đồng bộ hóa bao gồm toArray(). Xem các khối mã bên dưới, lấy từ mã nguồn Java trong java.util.Collections.SynchronizedCollection.

public Object[] toArray() { 
    synchronized(mutex) {return c.toArray();} 
} 

public <T> T[] toArray(T[] a) { 
    synchronized(mutex) {return c.toArray(a);} 
} 
+0

Không. Bạn phải dựa vào hợp đồng chứ không phải thực hiện. – Woot4Moo

+0

@ Woot4Moo Tôi đồng ý với bạn rằng người ta không nên dựa vào việc thực hiện, chỉ trên hợp đồng. Đoạn mã từ mã nguồn java là để cho một ý tưởng rõ ràng hơn về những gì đang thực sự xảy ra. Các JavaDoc nêu rõ _Returns một bộ sưu tập đồng bộ (thread-safe) được hỗ trợ bởi collection_ được chỉ định, được hiểu là tất cả các phương thức trên collection được trả về đều được đồng bộ hóa. Tôi không nghĩ có bất kỳ sự mơ hồ nào trong tài liệu về điều đó. – IceMan

+0

nếu bạn đọc toàn bộ tài liệu, rõ ràng trạng thái lặp phải được đồng bộ hóa. Nếu bạn có thể chuyển đổi giữa các cấu trúc dữ liệu mà không cần lặp lại, vui lòng chỉ cho tôi. – Woot4Moo

0

Dường như có một quan niệm sai lầm lớn xảy ra ở đây mà bạn có thể dựa vào việc triển khai mã nguồn thực tế. Điều này là sai, bạn phải dựa vào hợp đồng của phương pháp. Vì hợp đồng không tồn tại, bạn không thể giả định nó sẽ làm điều gì đó, tại bất kỳ thời điểm nào việc triển khai cơ bản có thể thay đổi. Ví dụ: xem xét chức năng sau:

/** 
* Returns an empty Collection of Books. 
* 
* 
*/ 
public Collection returnEmptyBooks() 
{ 
    return new HashSet<Book>(); 
} 

Điều này ngụ ý tôi có thể trả lại bất kỳ thứ gì triển khai giao diện Bộ sưu tập. Chữ ký cộng với tài liệu. Bạn không thể cho rằng nó được đồng bộ hóa hay bất kỳ thứ gì khác của bản chất đó. Bạn cũng có thể suy ra rằng bạn sẽ không bao giờ nhận được null trở lại từ phương pháp này, trừ khi hợp đồng đã bị vi phạm.

Trong trường hợp không ai đọc nhận xét. Bất kỳ chuyển đổi nào từ một cấu trúc dữ liệu sang cấu trúc dữ liệu khác đều ngụ ý lặp lại. Bạn không thể di chuyển từ List to Set mà không cần lặp qua tất cả các phần tử. Điều tương tự cũng áp dụng với một chuyển đổi thành một mảng. Bạn phải điền vào mảng bằng cách lặp qua cấu trúc dữ liệu ban đầu của bạn, do đó nó cần được đồng bộ hóa.

+0

Tôi không nghĩ rằng tôi nhận được quan điểm của bạn. Nếu theo hợp đồng bạn có nghĩa là nghiêm chỉnh chữ ký của một phương pháp, sau đó trong ví dụ của bạn ở trên nó không đúng là trả về null từ 'returnEmptyBooks()' là vi phạm hợp đồng. Trong thực tế, bất kỳ phương thức nào trả về bất kỳ java.lang.Object nào cũng có thể trả về null và nó có thể chỉ là một quy ước ** để trả về Bộ sưu tập rỗng và không rỗng. Quy ước này là thực hiện cụ thể và bởi lý do của bạn, bạn không nên tin tưởng nó. – artur

+0

@artur Hợp đồng có nghĩa là chữ ký + tài liệu. Nếu bạn nhìn vào tài liệu được cung cấp, nó nêu rõ nó sẽ trả về một Bộ sưu tập Sách trống. Lý do của tôi vẫn đứng như một đoạn mã mà sẽ gọi điều này sẽ được đảm bảo để nhận được một Bộ sưu tập rỗng và không phải là rỗng. Nếu null được trả lại, nó sẽ là một vi phạm hợp đồng. Có rất nhiều thứ đi vào DbC hơn là chỉ khai báo hàm. – Woot4Moo

+0

Tôi nhận được ya. Nhưng quay trở lại câu hỏi ban đầu của tôi, javadoc nói rõ ràng _ trả lại một bộ sưu tập được đồng bộ hóa (thread-safe). Dựa trên điều này bạn vẫn không hài lòng rằng bạn có thể giả định rằng toArray() của bộ sưu tập được truyền lại được đồng bộ hóa và threadsafe? – artur

Các vấn đề liên quan