-1

So, the scenario is like:

//Some code...

public Map<String, String> someFunction() {
    for (final UserDetail user : userDetailList) {
        // the following (below) code runs in background thread
        // long running task
        new RecordPersonalisedDao().getPendingRecordsForUid(user.getuId(), new RecordPersonalisedDao.OnResultFetched() {
            @Override
            public void onResult(Result result) {
                // callback after the user is processed
                // put some parameter from result to map
                map.put(user.getName(), result.getTotal());
            }
        });
    }
    // return map only after all users are processed
    return map;
}

As mentioned in the comment of above piece of code, I want the final map to be returned only after the entire list of user is processed.

I cannot change the functionality of RecordPersonalisedDao#getPendingRecordsForUid so as to make it run in the main thread only.

How do I achieve this in java ?

Edit: This type of problem can be faced in general. So, I want to understand the solution for the same in java.

To put my question simply, I want behaviour like

  • Run this code in background for all members in the array, and once it's done, send a callback.

(Roughly like)

[list_of_some_data]
    .forEach( run this function )
    .after(after the function is run in background for  all members of list - return some value)
Sumit Jha
  • 2,095
  • 2
  • 21
  • 36
  • Possible duplicate of [thread safe map for java](https://stackoverflow.com/questions/1792023/thread-safe-map-for-java) – Scrambo Sep 11 '17 at 13:25
  • 1
    Use join() method to wait until background thread is completed. – Supun Amarasinghe Sep 11 '17 at 13:31
  • 2
    What you want is an ExecutorService and to use the Future that is returned by submitting a task as your callback. – bhspencer Sep 11 '17 at 13:36
  • 1
    If I understand correctly then you want to use `Future` and use `CompletableFuture.allOf` in order to wait for all the `Future`s. See here https://stackoverflow.com/a/36261808/3883957. – yishaiz Sep 11 '17 at 13:38

2 Answers2

1

Before the loop, create a CountdownLatch with a count equal to the user list length. Inside the result handler, count down after updating the map. After the loopawait() the latch to be counted down, then return.

erickson
  • 265,237
  • 58
  • 395
  • 493
  • The real question is how to do things in parallel. I really don't see how your "answer" answers that. Don't get me wrong ... but I guess you didn't collect your 200K reputation by giving such answers, did you? – GhostCat Sep 11 '17 at 15:03
  • @GhostCat The question very clearly states that `getPendingRecordsForUid()` runs in a background thread, and that the question, more generally, is how to block until all background tasks have completed—under the constraint that you can't change the task itself. – erickson Sep 11 '17 at 15:41
  • E.g., "the following (below) code runs in background thread," "I cannot change the functionality of RecordPersonalisedDao#getPendingRecordsForUid so as to make it run in the main thread only," and "return map only after all users are processed" – erickson Sep 11 '17 at 16:03
  • 1
    Thank you Sir :) Used ``CountDownLatch`` to solve the same. – Sumit Jha Sep 11 '17 at 18:09
1
public Map<String, String> someFunction() {
    CountDownLatch cdl = new CountDownLatch(userDetailsList.size());
    for (final UserDetail user : userDetailList) {
        // the following (below) code runs in background thread
        // long running task
        new RecordPersonalisedDao().getPendingRecordsForUid(user.getuId(), new RecordPersonalisedDao.OnResultFetched() {
            @Override
            public void onResult(Result result) {
                // callback after the user is processed
                // put some parameter from result to map
                map.put(user.getName(), result.getTotal());

                //We're done grabbing the results.. count down.
                cdl.countDown();
            }
        });
    }

    //Block this thread until all the results are in.
    cdl.await();

    return map;
}
Eladian
  • 958
  • 10
  • 29