0

I am executing millions of iteration and I want to parallelize this. Hence decided to add the task [each iteration] to the Thread Pool.

Now, if I add all the iteration to the Thread Pool, it might throw an OutOfMemoryError. I want to handle that gracefully, so is there any way to know about the availability of the worker Thread in the Thread Pool?

Once it's available, add the Runnable to the Worker Thread.

for(int i=0; i<10000000000; i++) {
     executor.submit(new Task(i));
}

Each of those tasks merely take 1 sec to complete.

msrd0
  • 7,816
  • 9
  • 47
  • 82
surendhar_s
  • 824
  • 2
  • 12
  • 20
  • A thread pool comes with a queue of tasks. Once the queue is full, it can reject the task, or block the task submitting thread. Read the javadoc: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html – JB Nizet Aug 25 '14 at 19:41
  • I want to create a task like this, say i have my own separate queue that contains the data enough to create a task[runnable].. If the worker thread is available, I will dequeue the data from my queue.. Then create a runnable from that data and add it to the executor. – surendhar_s Aug 25 '14 at 19:43
  • Sorry, I just realized that none of the rejection policies consists in blocking the calling thread. That said, the CallerRunsPolicy can be what you need. – JB Nizet Aug 25 '14 at 19:49
  • See also http://stackoverflow.com/questions/2001086/how-to-make-threadpoolexecutors-submit-method-block-if-it-is-saturated – JB Nizet Aug 25 '14 at 19:53
  • Ten billion tasks at a _mere_ one second each is more than 316 years of compute time. How many CPUs do you have to split up that workload? – Solomon Slow Aug 25 '14 at 19:58

3 Answers3

0

Why don't you set a limit to how many tasks can run concurrently. Like:

HashSet<Future> futures = new HashSet<>();
int concurrentTasks = 1000;

for (int ii=0; ii<100000000; ii++) {
    while(concurrentTasks-- > 0 && ii<100000000) {
        concurrentTasks.add(executor.submit(new Task(ii)));
    }
    Iterator<Future> it = concurrentTasks.iterator();
    while(it.hasNext()) {
        Future task = it.next();
        if (task.isDone()) {
            concurrentTasks++;
            it.remove();
        }
    }
}
Jean Waghetti
  • 4,711
  • 1
  • 18
  • 28
0

You'll want to use something like this:

ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(MAX_PENDING_TASKS);
Executor executor = new ThreadPoolExecutor(MIN_THREADS, MAX_THREADS, IDLE_TIMEOUT, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.CallerRunsPolicy());

for(int i=0; i<10000000000; i++) {
  executor.submit(new Task(i));
}

Basically you create a thread pool with min/max threads and an array backed queue. When you hit the limit of pending tasks, the "caller runs policy" kicks in and your main thread ends up running the next task (giving time for your other tasks to complete and open slots in the queue).

Since you've stated that your tasks are short lived, this seems like an optimal strategy.

The values for MAX_PENDING_TASKS and MIN_THREADS are something you can fiddle with to figure out what the optimal values are for your workload, but MAX_PENDING_TASKS should be at least twice MIN_THREADS and probably more like 10 to 100 times.

Alcanzar
  • 16,985
  • 6
  • 42
  • 59
-1

You should use java.lang.Runtime

The biggest memory issue is probably going to be your Object creation, not in adding them to your Executor, so that's where you should be calling Runtime.getRuntime().freeMemory().

msrd0
  • 7,816
  • 9
  • 47
  • 82
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80