Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing existing foreach loop on ConcurrentHashMap to use Lambdas to harness parallel processing

I am making a game and have a ConcurrentHashMap which contains all the players which are currently logged in. I have a AutoSaver thread which loops through the HashMap and saves all the player 1 by 1. When there are not many players this is fine as it doesn't take too much time to iterate but it can slow down a bit when there are many players logged in. I read using java stream and parallel, we can speed up processing of collections, so I tried changing my existing loop to now use stream and parallel.

My question is, is my implementation correct? Is there a better way to do it? Is it thread safe now?

Here is the existing implementation

for(Player player : ActiveConnections.getAllConnectedPlayers().values(){
    if(player != null)
        saveManager.savePlayer(player, true);
}

Here is my implementation using stream and parallel

ActiveConnections.getAllConnectedPlayers().values()
    .stream()
    .parallel()
    .filter((x) -> x != null)
    .forEach((x) -> saveManager.savePlayer(x, true));

EDIT Here is my save manager implementation

public class SaveManager {

    private MySqlManager sqlManager;

    public SaveManager(){
        sqlManager = MySqlManager.getInstance();
    }

    public void savePlayer(Player player, boolean autoSave){
       //Saves the player
    }

Again I have just started using lambdas so please let me know if there is something wrong.

like image 925
Sneh Avatar asked Nov 09 '22 10:11

Sneh


1 Answers

It is thread safe if savePlayer is thread save. turning a stream into a parallel one doesn't make it thread safe, it makes the algorithm able to be parallelized.

However, if your savePlayer save stuff in the data base, then there is no way to parallelize the player saving part which is what you would like. Meaning that you'll see no benefit from using a parallel stream because when one thread changes the contents of the DB, two things can happen:

  • the second thread that wants to save another player, waits for the first thread to finish. If this is the case, then there is no benefit of using parallel streams because threads still have to wait for each other.

  • the second thread attempts to change DB data at the same time has the first thread which may lead to incoherent data on your Database. Assuming your code supports more than one active connection to the database.

In sum, you should use parallel stream when the algorithm you want to execute is parallelizable. Internally, parallelStream() divides the stream into sub-streams, and executes the algorithm for each item on each of the sub-streams (concurrently), in the end the result of each sub-stream is combined using the same algorithm.

An example from the "Java 8 in Action" book:

public static long parallelSum(long n){
   return Stream.iterate(1L, i -> i + 1) // generate a stream of long values, starting at 1
                .limit(n) // limit the stream to n items
                .parallel()
                .reduce(0L, Long::sum); // this is what we want to execute concurrently, and in the end the result of each sub-stream will be combined using this sum
}

For more information refer to chapter 7 of the book.

like image 116
pedromss Avatar answered Nov 14 '22 21:11

pedromss