How to run sequential Tasks in an ExecutorService

Heirteir :

I would like to execute different tasks for each player in an event executor, but make sure that the tasks submitted for each player are in order. Here is a picture to hopefully explain in better.

Visual representation of what I am trying to accomplish

Extra Information:

  1. I know which player will be effected for each task
  2. I receive the tasks for each player in a pseudo-random order. (I will not know the order of task input before hand)
  3. I need each player to basically have their own "thread" so that their tasks execute in order of insertion.

What I have tried:

Currently I am using Executors.newSingleThreadExecutor() inside of each player object to mimic this functionality, but I don't think this will scale well with a lot of players. Hence why I am asking here to find a better method.

GPI :

I see three main ways of achieving this.

Thread per player

This is a bit like what you are doing. Create a thread per player, dispatch work units to it; this is serial by nature.

It may not scale well to a few hundreds / thousands of players (a few hundred active threads usually do not scare mordern hardware - although it may not be really efficient).

But the readability and ligthness of the code will probably be unmatched by other solutions.

Shared threads with consistent routing

If a thread per player is not possible, then we will have to share threads, and a thread will deal with several players.

The key will be to have a given thread handle every task for a given player, so as to achieve serial execution.

Three ways of building this come to mind...

Create groups of players

If your players have something to allow for grouping (e.g. a Team, or even just a creation date)... then regroup your players by group, and implement a "Thread per group" pattern.

The only key issue is to have groups of roughly the same size, so as to share the load evenly.

Another issue, that you will have in almost every solution, will be to shutdown the thread for the group (how do you know when everything you wanted to process is finished ?).

Shared threads and ExecutorService

This is the "do it yourself way". The gist of it is

  1. create a fixedThreadPool, say with 4 threads.
  2. Create a 4 BlockingQueue that will hold every work units
  3. Create 4 PlayerWorker instances and send them to the thread pool to being execution, one for each of the above BlockingQueue. The implementation of these workers is to pull data from one of the queues and execute it.
  4. Dispatch your player work units by sending them to the queue. The key here is to always reuse the same queue for the same player (e.g. if your player has an identifier property, say a long, then dispatch all work units to the Math.abs(id % 4)th queue
  5. Shut down the PlayerWorker and thread pool when everything is done

This is a lot of work, so...

Using a framework

Some people have already done it for you. The actor pattern is a very good fit for this problem. You should probably check out Akka and what is called ConsistentHashingRoutingLogic, which is a pretty much one to one mapping, conceptually at least, to what I just described.

The reactive way

If we step back a bit, we do not actually care about threads. We care about serial execution.

So we just need a way to perform some work after some other work is done. It should be just a call back !

And we have CompletableFuture for that (not to mention frameworks).

So why not create one CompletableFuture per player, and each time a new work unit is to be done for this player, use CompletableFuture.thenApply or thenApplyAsync.

By dispatching the executions to an appropriately sized execution pool, and letting the framework do the job, the tasks will be serially executed one after the other.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=420387&siteId=1