Sudheer
Sudheer

Reputation: 327

Creating too many threads in Java

I am using threads in my Java application to partially get the data (using network calls). I have a method (which is not in a threaded class), which creates a thread pool with given size (10-15 maximum) and uses them for network calls, and I am calling that method several times from a loop.

When I am running this application on a slow machine (3 GB RAM, Pentium-IV), everything works fine, but when I run it on an iMac (32 GB RAM, i7 processor), it is creating too many threads, about 2,500 sometimes and throwing an out-of-memory error.

I suspect that the JVM is not putting back the completed threads back in to the pool as soon they are finished, hence it's creating new threads.

And even on the iMac, if I keep Thread.sleep(1000); in the for loop which I mentioned above everything works fine. Creating about 900 threads though.

Below are the code samples from this application:

public ArrayList<String> getValuesForKeyFromMaps(String key, ArrayList<Meta> locations) throws InterruptedException, ExecutionException {

    int threadNum = locations.size(); // 10-15 at max

    ExecutorService executor = Executors.newFixedThreadPool(threadNum);
    List<FutureTask<ArrayList<String>>> taskList = new ArrayList<FutureTask<ArrayList<String>>>();

    for(final Meta location : locations){

        FutureTask<ArrayList<String>> futureTask_1 = new FutureTask<ArrayList<String>>(new Callable<ArrayList<String>>() {
            public ArrayList<String> call() throws Exception {
                // Service call
                return getValues(key, location);
            }
        });
        taskList.add(futureTask_1);
        executor.execute(futureTask_1);

    }

    ArrayList<String> values = new ArrayList<String>();

    // Wait until all results are available and combine them at the same time
    for (int j = 0; j < threadNum; j++) {
        FutureTask<ArrayList<String>> futureTask = taskList.get(j);
        values.addAll(futureTask.get());
    }
    executor.shutdown();
    return values;
}

If I call the above method using below for loop on iMac, it throws a memory error, since it's creating about 2,500 threads. But it works fine on the slower machine.

    for(String key : keySet){
        getValuesForKeyFromMaps(key, metaMap.get(key));
    }

And, with the below code, on iMac it's working fine with about 900 threads.

    for(String key : keySet) {
        getValuesForKeyFromMaps(key, metaMap.get(key));
        Thread.sleep(200); // Sleeping for 200 ms
    }

If I increase sleep time in the above for loop to 1000&nbsp;ms, it's creating only 30-50 threads and the application is working fine.

How do I control maximum threads allowed in my application? I am intending to create/use 10-15 threads at the maximum at a given time, but Java is creating too many.

Upvotes: 6

Views: 9843

Answers (2)

Dariusz
Dariusz

Reputation: 22271

It's not Java that's creating too many threads; you are!

Don't create an executor each time you call a function. If you have 100 collections with 100 elements each, you will create 10,000 threads - that is very resource-consuming... And pointless.

ExecutorService executor = Executors.newFixedThreadPool(threadNum);

You have, most likely, 8 cores - just create one executor with 8 threads and use it everywhere. Your code will work faster and your application will consume less, much much fewer resources.

Familiarize yourself with this code review singleton executor question. You may be able to use that solution in your application.

Upvotes: 6

piet.t
piet.t

Reputation: 11921

By using ExecutorService executor = Executors.newFixedThreadPool(threadNum); you are creating a new thread pool for each call of getValuesForKeyFromMaps. So when your keySet contains 100 entries you'll end up with 100 pools with 10-15 threads each. Keep one thread-pool as an instance- or class-variable and use it whenever needed.

Upvotes: 3

Related Questions