2015-05-27 19 views
12

Mã của tôi:StringBuilder có an toàn không (sử dụng nó với parallelStream)?

StringBuilder sb = new StringBuilder(); 

events.parallelStream().forEach(event -> { 
    sb.append(event.toString()); 
    sb.append("\n"); 
}); 

Tôi không quan tâm đến thứ tự của các events.toString() trong kết quả cuối cùng. Nhưng tôi quan tâm rằng các events.toString() sẽ xuất hiện một cách chính xác một dòng khác, mà không cần trộn/rối lên tất nhiên.

parallelStream (thay vì stream) có an toàn trong vấn đề này không?

+1

Thậm chí nếu bạn đã sử dụng StringBuffer, bạn có thể nhận được hai sự kiện liên tiếp và sau đó hai dòng mới trong một hàng. – Random832

+0

Câu trả lời là không. (có thể hữu ích: [Làm thế nào để chứng minh theo lập trình rằng StringBuilder không phải là luồng an toàn?] (https://stackoverflow.com/questions/48558432)) – Andrew

Trả lời

17

Các giải pháp tốt hơn là sử dụng

events.parallelStream().map(event -> event+"\n").collect(Collectors.joining()); 

Hoặc cách khác (nhờ @Holger):

events.parallelStream().map(Object::toString).collect(Collectors.joining("\n", "", "\n")); 

Trong tránh nói chung sử dụng forEach hoạt động như thiết bị đầu cuối cho suối. Các hoạt động giảm thông thường như collect hoặc reduce là các lựa chọn thay thế tốt hơn.

+0

Liệu việc thu thập các chuỗi có xảy ra sau khi tất cả công việc của các luồng song song hay ở giữa nó không? Bởi vì tôi nghĩ rằng 'parallelStream' sử dụng fork join framework đằng sau hậu trường. –

+0

Nhiệm vụ sẽ được chia thành các phần và chúng sẽ được tham gia song song độc lập. Cuối cùng, các phần sẽ được hợp nhất với nhau thành chuỗi kết quả. Nó sử dụng 'StringBuilder' trong nội bộ, nhưng các phần khác nhau sử dụng các cá thể khác nhau, do đó không có vấn đề gì với việc đồng bộ hóa ở đây. –

+6

Vẫn còn tốt hơn: 'events.parallelStream(). Map (Object :: toString) .collect (Collectors.joining (" \ n "," "," \ n "));' – Holger

4

Không, không phải. Như đã lưu ý trong its javadoc:

Chuỗi ký tự có thể thay đổi. Lớp này cung cấp một API tương thích với StringBuffer, nhưng không đảm bảo đồng bộ hóa.

Sử dụng StringBuffer để thay thế.

+2

Lưu ý rằng bạn sẽ không được hưởng lợi từ việc song song nếu bạn sử dụng 'StringBuffer' trong trường hợp. Tôi khá chắc chắn nó sẽ thậm chí còn chậm hơn so với dòng tuần tự như thực sự không có gì sẽ được thực hiện song song; tất cả các chủ đề ngoại trừ một chủ đề sẽ chỉ chờ đợi trên màn hình. –

+0

@TagirValeev Điều đó không đúng. Các phương thức toString của sự kiện sẽ được thực hiện song song. – Random832

8

Không, thiết bị không an toàn.

Đây là sự khác biệt chính giữa số StringBuffer cũ và StringBuilder mới - các phương pháp trước đây được đồng bộ hóa, trong khi phương pháp sau không được đồng bộ hóa.

Nó không phải là rất hữu ích để làm điều đó theo cách này, ngay cả khi bạn muốn sử dụng StringBuffer thay thế - các chủ đề sẽ phải chờ đợi để viết cho StringBuffer.

+4

Và đừng quên, ngay cả khi sử dụng 'StringBuffer', hai lệnh' append' được thực hiện trong biểu thức lambda có thể được xen kẽ tùy ý khi biểu thức lambda được thực hiện đồng thời mà không cần đồng bộ hóa bổ sung. – Holger

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