2

Looking for an approach to solve a multi threading problem. I have N number of tasks say 100. I need to run this 100 tasks using limited number of threads say 4. Task size is huge , so I dont want to create all the tasks together. Each task will be created only when a free thread is available from the pool. Any recommended solution for the same.

rvp
  • 580
  • 4
  • 7
  • 21
  • Use a executor service/thread pool. Take a look at this: https://stackoverflow.com/questions/3286626/what-is-the-use-of-a-thread-pool-in-java, and https://stackoverflow.com/questions/8767527/how-to-use-thread-pool-concept-in-java – ernest_k Feb 06 '19 at 18:03
  • [`Executors.newFixedThreadPool(int nThreads)`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int-)? – MTCoster Feb 06 '19 at 18:04
  • @ernest_k: But all the implementations of executor service I was referring to, I could not find a way to wait for a free thread to create and execute the next task. – rvp Feb 06 '19 at 18:05
  • @MTCoster : it will create a thread pool of fixed size. But what if all the threads are executing some task and i need to wait for atleast 1 free thread to create and execute the new task. – rvp Feb 06 '19 at 18:06
  • @rvp Use a thread pool with a fixed number of threads, as suggested by MTCoster. You just submit all the tasks, but the executor service will schedule and run them as threads become available. – ernest_k Feb 06 '19 at 18:07
  • You create the threadpool with a fixed number of threads, then assign it as many tasks as you like - the whole point of a threadpool is it handles this logic for you – MTCoster Feb 06 '19 at 18:07
  • @MTCoster: I agree. But the task size is huge and hence i dont want to create all the tasks together since JVM may have heap overflow in my use-case . Nathan Hughes : As you mentioned, I will see if i can make use of the blockingQueue to add the newly created tasks. – rvp Feb 06 '19 at 18:11
  • “*may have heap overflow*” - have you tried it? It’s likely provisions in the runtime library were taken to avoid this kind of situation – MTCoster Feb 06 '19 at 18:12
  • The tasks themselves should work fine but the basic property of the thread pools is that the threads execute a queue of tasks, when a thread finishes a task it pulls the next one from the queue (which you added to). You don't actually touch the threads themselves. – Rogue Feb 06 '19 at 18:19

2 Answers2

3

You could use a BlockingQueue to define the tasks. Have one thread create the tasks and add them to the queue using put, which blocks until there's space in the queue. Then have each worker thread just pull the next task off of the queue. The queue's blocking nature will basically force that first thread (that's defining the tasks) to not get too far ahead of the workers.

This is really just a case of the producer-consumer pattern, where the thing being produced and consumed is a request to do some work.

You'll need to specify some way for the whole thing to finish once all of the work is done. One way to do this is to put N "poison pills" on the queue when the generating thread has created all of the tasks. These are special tasks that just tell the worker thread to exit (rather than doing some work and then asking for the next item). Since each thread can only read at most one poison pill (because it exits after it reads it), and you put N poison pills in the queue, you'll ensure that each of your N threads will see exactly one poison pill.

Note that if the task-generating thread consumes resources, like a database connection to read tasks from, those resources will be held until all of the tasks have been generated -- which could be a while! That's not generally a good idea, so this approach isn't a good one in those cases.

yshavit
  • 42,327
  • 7
  • 87
  • 124
1

If can get the number of active threads at a certain point of time from the thread pool you can solve your problem. To do that you can use ThreadPoolExecutor#getActiveCount. Once you have the number of the active thread then you can decide you should create a task or not.

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
executor.getActiveCount();

Note: ExecutorService does not provide getActiveCount method, you have to use ThreadPoolExecutor. ThreadPoolExecutor#getActiveCount Returns the approximate number of threads that are actively executing tasks.

Amit Bera
  • 7,075
  • 1
  • 19
  • 42