2016-12-20 22 views
5

Tôi có một số List cần phải gọi bằng nhiều chuỗi. Sẽ chỉ có một nhà văn duy nhất, và nhà văn này sẽ thêm các yếu tố và không làm gì khác. Các yếu tố không bao giờ bị xóa hoặc sửa đổi. Nhiều chủ đề đọc đồng thời sẽ gọi list.size()list.get(index).Có thể cho ArrayList thất bại trong một hệ thống độc giả đa người đọc không?

Chúng ta phải giả định rằng đôi khi mảng nội bộ sẽ cần phải phát triển khi các phần tử được thêm vào.

Tôi có thể lấy đi bằng cách sử dụng đồng bằng ArrayList hay tôi cần triển khai một số cấu trúc đồng thời ưa thích để tránh ngoại lệ?

+3

"Cấu trúc đồng thời ưa thích" ... Có ['ReadWriteLock'] (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReadWriteLock.html) nó gần như tầm thường để thực hiện. – aioobe

+3

Đối tượng có bị đột biến không? Đánh dấu. Nó có được truy cập bởi nhiều luồng không? Đánh dấu. Đối tượng có đi kèm với bất kỳ đảm bảo an toàn luồng nào không? Không. Xin chúc mừng, bạn cần một số loại đồng bộ hóa! Danh sách kiểm tra thực sự là đơn giản. – biziclop

+0

Bạn có quan tâm đến thứ tự chèn không? – Makoto

Trả lời

-1

Đề nghị của tôi là sử dụng semaphore để tránh bất kỳ ngoại lệ, theo cách mà bạn có thể kiểm soát độc giả đang đọc danh sách ở bất kỳ thời điểm

+2

Semaphores dường như không phải là lựa chọn đúng ở đây. Tôi muốn dùng [ReadWriteLock'] (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReadWriteLock.html). – aioobe

3

Nếu độc giả của bạn tất cả cần phải được đọc cùng một bang của List, có nghĩa mà người viết không thể viết giữa tất cả người đọc đọc, sau đó có, bạn sẽ cần phải sử dụng ReadWriteLock hoặc một số phương pháp phức tạp hơn để xử lý trường hợp này.

Nếu bạn không tha cho việc sử dụng bộ nhớ, đừng lo lắng nếu người đọc của bạn luôn có dữ liệu mới nhất và mục tiêu duy nhất của bạn là tránh trường hợp ngoại lệ, hãy xem xét CopyOnWriteArrayList, được xây dựng để tránh ngoại lệ xung đột ghi/lặp. Khi bạn viết thư này List, nó tạo một cái mới làm kết quả đã hoàn tất nhưng người đọc hiện đang sử dụng số List tiếp tục đọc chữ "cũ" (viết trước) thay thế.

+3

Tôi sẽ sử dụng một bộ tiêu chí khác để quyết định: với 'CopyOnWriteArrayList', thêm một phần tử khá đắt tiền và tốn nhiều chi phí hơn bạn có (vì bạn cần sao chép toàn bộ mảng sao lưu vào một vị trí mới mỗi lần), trong khi 'size()' và 'get()' là giá rẻ. Trong khi với các cấu trúc đồng thời "thông thường", chi phí bổ sung được trải ra giữa 'add()', 'size() 'và' get()'. Vì vậy, nếu danh sách của bạn hiếm khi được sửa đổi nhưng được truy vấn rất nhiều, hãy thực hiện copy-on-write. Nếu không thì không. – biziclop

+0

@biziclop tóm tắt tốt đẹp, tôi nên bao gồm điều đó. Đó là một điểm rất quan trọng mà 'CopyOnWriteArrayList' là tốt nhất cho các tình huống mà bạn hiếm khi viết và thường đọc. – Zircon

+0

Yup, bạn nói đúng, sẽ cần một khóa hoặc một chương trình copy-on-write. Phân tích này cho thấy rằng khi chỉ có một nhà văn đồng bộ hóa đồng bộ cũ hoạt động khá tốt: http://blog.takipi.com/java-8-stampedlocks-vs-readwritelocks-and-synchronized/ – ccleve

1

Vì vậy, trước hết tài liệu cho ArrayList nói rằng nó không phải là chủ đề an toàn, vì vậy tôi sẽ không khuyên bạn nên sử dụng nó trong trường hợp như vậy. Hơn nữa, ngay cả khi lý thuyết này có tác dụng, bạn vẫn có vấn đề đảm bảo rằng bất cứ ai duy trì chương trình này nhớ lại những ràng buộc nghiêm ngặt mà bạn đã áp đặt khi đọc và viết với sự vui nhộn sau đó nếu họ không làm vậy! Điều đó nói rằng, câu hỏi của bạn là thực sự thú vị từ một quan điểm lý thuyết vì vậy tôi nghĩ rằng tôi muốn có một cái nhìn. Điều đầu tiên cần lưu ý là bất kỳ độc giả nào đã cố gắng truy cập danh sách thông qua một trình lặp, sau đó sớm hay muộn, việc đọc sẽ thất bại với một ConcurrentModificationException. Đó là bởi vì mọi sửa đổi đối với danh sách được theo dõi và Iterator không nhanh nếu nó phát hiện một sửa đổi bên ngoài trình lặp.

Điều đó nói rằng, bạn không chỉ định nhu cầu sử dụng trình vòng lặp trong câu hỏi ban đầu của bạn vì vậy điều gì sẽ xảy ra nếu bạn hạn chế mình chỉ cần thêm bằng cách thêm và đọc bằng get() và size()? Trong trường hợp này tôi vẫn nghĩ bạn có thể thấy sự thất bại không thường xuyên vì trong danh sách lưu trữ kích thước hiện tại cùng với mảng dữ liệu sao lưu và không biến nào được đánh dấu là dễ bay hơi. Kết quả là (và do bảo đảm bộ nhớ của Java) tôi sẽ nghĩ rằng về mặt lý thuyết có thể cho một trong các chủ đề đọc để xem một biến kích thước cập nhật trong khi dữ liệu vẫn chưa được cập nhật. Trong trường hợp này, bạn có thể kết thúc dữ liệu rác được trả lại hoặc thậm chí là indexOutOfBounds.

+0

Vâng, chính xác. JVM có thể sắp xếp lại các lệnh và tạo ra vấn đề chính xác mà bạn mô tả. – ccleve

1

Nếu bạn mở để sử dụng thư viện của bên thứ ba, Eclipse Collections có loại được gọi là MultiReaderFastList hỗ trợ nhiều người đọc và một người viết. Nó ném trên iterator. Nếu bạn cần lặp lại, hãy tìm cách sử dụng một trong nhiều phương thức lặp nội bộ, điều đó sẽ an toàn có được khóa đọc và giải phóng nó sau khi lặp lại hoàn tất. Nếu bạn cần viết mã lặp lại bắt buộc, có hai phương thức có tên là withReadLockAndDelegatewithWriteLockAndDelegate sẽ cho phép bạn sử dụng khóa an toàn iterator trước và sau khối mã của bạn.

Lưu ý: Tôi là người ủy nhiệm cho Eclipse Collections.

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