2013-10-22 32 views
25

JDK 8 EA hiện đã hết và tôi chỉ đang cố gắng làm quen với lambda và API luồng mới. Tôi đã cố gắng để sắp xếp một danh sách với dòng song song, nhưng kết quả luôn luôn là sai:java 8 parallelStream() với sắp xếp()

import java.util.ArrayList; 
import java.util.List; 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     List<String> list = new ArrayList<>(); 
     list.add("C"); 
     list.add("H"); 
     list.add("A"); 
     list.add("A"); 
     list.add("B"); 
     list.add("F"); 
     list.add(""); 

     list.parallelStream() // in parallel, not just concurrently! 
      .filter(s -> !s.isEmpty()) // remove empty strings 
      .distinct() // remove duplicates 
      .sorted() // sort them 
      .forEach(s -> System.out.println(s)); // print each item 
    } 
} 

OUTPUT:

C 
F 
B 
H 
A 

Lưu ý rằng mỗi lần ra là khác nhau. Câu hỏi của tôi là, nó là một lỗi? hoặc là không thể sắp xếp một danh sách song song? nếu có, thì tại sao JavaDoc không nói điều đó? Câu hỏi cuối cùng, có một hoạt động khác có đầu ra sẽ khác nhau tùy thuộc vào loại luồng không?

+1

Có thể sẽ tốt hơn nếu xóa các mục trùng lặp sau khi sắp xếp. – Ingo

Trả lời

44

Bạn cần sử dụng forEachOrdered, không phải forEach.

Theo forEach doc:

Đối với đường ống dẫn dòng song song, hoạt động này không đảm bảo tôn trọng trật tự cuộc gặp gỡ của con suối, vì làm như vậy sẽ hy sinh vì lợi ích của xử lý song song. Đối với bất kỳ phần tử nào, hành động có thể được thực hiện bất cứ lúc nào và trong bất kỳ chủ đề nào mà thư viện chọn. Nếu hành động truy cập trạng thái được chia sẻ, nó có trách nhiệm cung cấp đồng bộ hóa cần thiết.

+1

+1 Lộng lẫy! Đây là những gì tôi đang tìm kiếm. –

+0

Đoán của tôi là nội bộ nó tạo ra một danh sách "sắp xếp", mỗi chủ đề thêm vào danh sách đó, sau đó tiếp tục bước tiếp theo trong luồng (forEach) để nó thực thi theo thứ tự, FWIW. – rogerdpack

6

Ngoài ra, bạn có thể đọc thêm về chủ nghĩa song song và forEachOrdered với một ví dụ rất hay từ here. Tóm lại, sử dụng forEachOrdered trong một luồng song song có thể dẫn đến mất lợi ích của tính song song.

Ở đây, ví dụ từ các nguồn giống nhau:

Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 }; 
List<Integer> listOfIntegers = 
    new ArrayList<>(Arrays.asList(intArray)); 

System.out.println("listOfIntegers:"); 
listOfIntegers 
    .stream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("listOfIntegers sorted in reverse order:"); 
Comparator<Integer> normal = Integer::compare; 
Comparator<Integer> reversed = normal.reversed(); 
Collections.sort(listOfIntegers, reversed); 
listOfIntegers 
    .stream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("Parallel stream"); 
listOfIntegers 
    .parallelStream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("Another parallel stream:"); 
listOfIntegers 
    .parallelStream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("With forEachOrdered:"); 
listOfIntegers 
    .parallelStream() 
    .forEachOrdered(e -> System.out.print(e + " ")); 
System.out.println(""); 

Và đầu ra là

listOfIntegers: 
1 2 3 4 5 6 7 8 
listOfIntegers sorted in reverse order: 
8 7 6 5 4 3 2 1 
Parallel stream: 
3 4 1 6 2 5 7 8 
Another parallel stream: 
6 3 1 5 7 8 4 2 
With forEachOrdered: 
8 7 6 5 4 3 2 1 

Đường ống dẫn dầu thứ năm sử dụng phương pháp forEachOrdered, mà xử lý yếu tố của dòng trong thứ tự được chỉ định bởi nguồn của nó, bất kể bạn đã thực thi luồng theo chuỗi hoặc song song hay chưa. Lưu ý rằng bạn có thể mất lợi ích của việc xử lý song song nếu bạn sử dụng hoạt động như forEachOrdered với suối song song

.

+0

Đó là một chút mỏng. Vui lòng mở rộng câu trả lời của bạn bằng cách chỉnh sửa câu trả lời. –

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