How to process nested list of objects in JAVA 8 - process inner list sequentially, while the outer list has to be processed parallel

Viewed 192

I am trying to solve the below situation : I have a nested list of custom objects. I have to process the outer list parallel but the inner list objects has to be processed in sequence. I tried list.parallelstream() for the outer list and list.stream() for the inner list but it not working, the inner list values are processed randomly during execution. I thought of using Thread (ExecutorService) but not sure how exactly to start with. Below is my code snippet for the paralalStream:

Code to process the list :

List<List<MyObject>> masterList = getMasterList();    
masterList.parallelStream().forEach(innerList -> printSubList(innerList));   

Code to populate the list:

private static List<List<MyObject>> getMasterList() {
    MyObject myObject1 = new MyObject(1,"ABC-1");
    MyObject myObject2 = new MyObject(2,"ABC-2");
    MyObject myObject3 = new MyObject(3,"ABC-3");
    MyObject myObject4 = new MyObject(1,"XYZ-1");
    MyObject myObject5 = new MyObject(2,"XYZ-2");
    
    List<MyObject> innerList1 = new ArrayList<>();
    
    innerList1.add(myObject1);
    innerList1.add(myObject2);
    innerList1.add(myObject3);
    
    List<MyObject> innerList2 = new ArrayList<>();
    innerList2.add(myObject4);
    innerList2.add(myObject5);                            
    List<List<MyObject>> masterList = new ArrayList<>();
    masterList.add(innerList1);
    masterList.add(innerList2);
    return masterList;
}

Print the object to verify :

private static Consumer<? super List<MyObject>> printSubList(List<MyObject> innerList) {        
    innerList.stream();
    for(MyObject myObject : innerList) {
        System.out.println("System Time = "+ System.currentTimeMillis()+" = "+myObject.getName()+" "+myObject.getId());
    }
    return null;
}

I am open to use Thread as well, but not sure how in this situation. Any help is really appreciated.

Here is my current output :

System Time = 1603173228270 = ABC-3 3                                   
System Time = 1603173228271 = XYZ-1 1                                    
System Time = 1603173228272 = ABC-1 1                                   
System Time = 1603173228272 = ABC-2 2                                   
System Time = 1603173228272 = XYZ-2 2

But I want it to be :

System Time = 1603173228270 = ABC-1 1                                   
System Time = 1603173228271 = ABC-2 2                                   
System Time = 1603173228272 = ABC-3 3                                   
System Time = 1603173228270 = XYZ-1 1                                                          
System Time = 1603173228271 = XYZ-2 2
2 Answers

Nice to reply to you. In this case, I thought your idea that is wrong in multiple threads. Because the process's consequence is not sure in multiple threads or the Parallelstream, every thread executes process may be using different times. So we can not control the order in the process, exceptionally, we make some logic to them, but it is not easy, besides, it is unnecessary. If you really want to use multiple threads to process these data. You can try to follow this.Using Executors.newSingleThreadExecutor. Thread threadA = new Thread(()->{ System.out.println("A"); });

Thread threadB = new Thread(()->{ System.out.println("B"); });

Thread threadC = new Thread(() -> { System.out.println("C"); });

ExecutorService executors = Executors.newSingleThreadExecutor();

`executors.submit(threadA);

executors.submit(threadB);

executors.submit(threadC);

executors.shutdown();`

// The answer always A B C

Your code is indeed "processing" the outer list in parallel and the inner list in sequence. It's just that you are also printing the lines in parallel, causing the output to appear out of order.

To fix, you should separate the logic of "processing objects" from "printing objects". Rather than having a printSublist that prints a sublist, have a stringFromSublist method that given a sublist, returns a string that should be printed for that sublist.

private static String stringFromSublist(List<MyObject> innerList) {
    return innerList.stream()
            .map(myObject -> "System Time = "+ 
                             System.nanoTime()+ // nanoTime gives you more resolution
                             " = "+myObject.getName()+
                             " "+myObject.getId())
            .collect(Collectors.joining("\n"));
}

Now you can use a map before forEachOrdered:

masterList.parallelStream()
    .map(Main::stringFromSublist) // assuming stringFromSublist is in a class called Main
    .forEachOrdered(System.out::println);

The map will be parallel. the forEachOrdered will be sequential.

Example output:

System Time = 20136256197640 = ABC-1 1
System Time = 20136285091800 = ABC-2 2
System Time = 20136285104398 = ABC-3 3
System Time = 20136256536459 = XYZ-1 1
System Time = 20136284789960 = XYZ-2 2
Related