Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how do you "ignore" java.util.concurrent.Future objects?

Can you spot the bug? This will throw an java.lang.OutOfMemoryError.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestTheads {

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newFixedThreadPool(1);
        while(true) {
            executorService.submit(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                    }
                }
            });
        }
    }

}

The bug is that I call executorService.submit() instead of executorService.execute(), because submit() returns a Future object I'm ignoring. With execute(), this program will actually run forever.

However, one does not always have the luxury of having an execute() method, like when using a ScheduledExecutorService:

public static void main(String[] args) {
    // this will FAIL because I ignore the ScheduledFuture object
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
    while(true) {
        executorService.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                }
            }
        }, 1, 1, TimeUnit.SECONDS);
    }
}

What is one supposed to do with tasks that don't return anything, only compute?

Any ideas would be grateful appreciated!

EDIT: ThreadPoolExecutors purge() looked promising, but it only purges cancelled tasks.

like image 361
The Alchemist Avatar asked Apr 28 '11 21:04

The Alchemist


1 Answers

The Future object that is returned is strongly referenced by the ExecutorService only until it is executed. (It is actually a FutureTask instance that delegates to your Runnable.) Once it has executed, it will be garbage collected, because the caller has no reference to it. In other words, the memory problem has nothing to do with the treatment of the Future.

If you are running out of memory, it is because the work queue has millions of tasks queued up. As with any queue, unless the average rate of consumption exceeds the average rate of production, the queue will fill up. The contents of the queue consume memory.

Use a bounded queue, which will effectively, throttle task queuing, or get more memory.

This code will run "forever":

  ExecutorService executorService = Executors.newFixedThreadPool(1);
  while(true) {
    executorService.submit(new Runnable() {
      public void run() {
        try {
          Thread.sleep(10);
        } catch (InterruptedException e) { }
      }
    });
    Thread.sleep(12);
  }

The difference is not in the treatment of the resulting Future instances, but that tasks are queued at a rate at which they can be processed.

like image 130
erickson Avatar answered Sep 22 '22 22:09

erickson