Hãy xem xét một List<String> stringList
cái có thể được in theo nhiều cách bằng cách sử dụng các cấu trúc Java 8 :
stringList.forEach(System.out::println); // 1) Iterable.forEach
stringList.stream().forEach(System.out::println); // 2) Stream.forEach (order maintained generally but doc does not guarantee)
stringList.stream().forEachOrdered(System.out::println); // 3) Stream.forEachOrdered (order maintained always)
stringList.parallelStream().forEach(System.out::println); // 4) Parallel version of Stream.forEach (order not maintained)
stringList.parallelStream().forEachOrdered(System.out::println); // 5) Parallel version ofStream.forEachOrdered (order maintained always)
Những cách tiếp cận này khác nhau như thế nào?
Cách tiếp cận đầu tiên ( Iterable.forEach
) -
Trình lặp của bộ sưu tập thường được sử dụng và được thiết kế để không nhanh , điều đó có nghĩa là nó sẽ ném ConcurrentModificationException
nếu bộ sưu tập cơ bản được sửa đổi cấu trúc trong quá trình lặp. Như đã đề cập trong tài liệu cho ArrayList
:
Một sửa đổi cấu trúc là bất kỳ hoạt động nào thêm hoặc xóa một hoặc nhiều phần tử hoặc thay đổi kích thước mảng sao lưu một cách rõ ràng; chỉ đơn thuần là thiết lập giá trị của một phần tử không phải là một sửa đổi cấu trúc.
Vì vậy, nó có nghĩa là để ArrayList.forEach
thiết lập giá trị được cho phép mà không có bất kỳ vấn đề. Và trong trường hợp thu thập đồng thời, ví dụ ConcurrentLinkedQueue
, trình lặp sẽ không nhất quán yếu, điều đó có nghĩa là các hành động được truyền vào forEach
được phép thực hiện ngay cả các thay đổi về cấu trúc mà không có ConcurrentModificationException
ngoại lệ bị ném. Nhưng ở đây các sửa đổi có thể hoặc không thể nhìn thấy trong lần lặp đó.
Cách tiếp cận thứ hai ( Stream.forEach
) -
Thứ tự không xác định. Mặc dù nó có thể không xảy ra cho các luồng liên tiếp nhưng đặc tả không đảm bảo nó. Ngoài ra, hành động được yêu cầu là không can thiệp vào tự nhiên. Như đã đề cập trong doc :
Hành vi của hoạt động này là không rõ ràng. Đối với các đường ống dòng song song, hoạt động này không đảm bảo tôn trọng thứ tự gặp gỡ của luồng, vì làm như vậy sẽ hy sinh lợi ích của song song.
Cách tiếp cận thứ ba ( Stream.forEachOrdered
) -
Hành động sẽ được thực hiện theo thứ tự bắt gặp của luồng. Vì vậy, bất cứ khi nào vấn đề đặt hàng sử dụng forEachOrdered
mà không có một ý nghĩ thứ hai. Như đã đề cập trong tài liệu :
Thực hiện một hành động cho từng thành phần của luồng này, theo thứ tự bắt gặp của luồng nếu luồng có thứ tự bắt gặp được xác định.
Trong khi lặp lại một bộ sưu tập được đồng bộ hóa , cách tiếp cận đầu tiên sẽ lấy khóa của bộ sưu tập một lần và sẽ giữ nó trên tất cả các phương thức gọi hành động, nhưng trong trường hợp các luồng chúng sử dụng bộ chia của bộ sưu tập, không khóa và dựa vào các quy tắc đã được thiết lập giao thoa. Trong trường hợp bộ sưu tập sao lưu luồng được sửa đổi trong quá trình lặp, một ConcurrentModificationException
kết quả sẽ bị ném hoặc không nhất quán có thể xảy ra.
Cách tiếp cận thứ tư (Song song Stream.forEach
) -
Như đã đề cập, không có gì đảm bảo tôn trọng thứ tự gặp gỡ như mong đợi trong trường hợp các luồng song song. Có thể hành động được thực hiện trong các luồng khác nhau cho các yếu tố khác nhau mà không bao giờ có thể xảy ra forEachOrdered
.
Cách tiếp cận thứ năm (Song song Stream.forEachOrdered
) -
Ý forEachOrdered
chí sẽ xử lý các phần tử theo thứ tự được chỉ định bởi nguồn bất kể thực tế là luồng là tuần tự hay song song. Vì vậy, nó không có ý nghĩa để sử dụng điều này với các luồng song song.
List
là? Chỉ cho chúng tôi cách bạn khai báo và khởi tạo nó.