Creating too many threads in Java
Asked Answered
G

2

6

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.

Gilli answered 3/12, 2015 at 8:5 Comment(4)
2500 or even 900 threads is a big deal. What do you want to do with that ?Hennie
see this: #764079Hennie
I don't see anything like "creating about 900 threads". You first create an executor with a number of threads fixed to locations.size(). Then you iterate through this locations collection and create one task per location, adding that to the thread pool. Either this locations size is much more than you thought, or you are only creating 10-15 (max) tasks. And ... by the way ... create the thread pool outside of this code snippet.Partlow
@guillaumegirod-vitouchkina I am not sure why its creating too many, I just want to use 10-15 based on size of valueset, for service calls.Gilli
F
6

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.

Florio answered 3/12, 2015 at 8:9 Comment(2)
While that is a good suggestion, look at the source code to find out how threadNum is initialized. I think, that is part of OP's problem.Partlow
Indeed, but the root of the problem is not understanding how to properly utilize threads. But since this site is about answering questions, and even the OP suspects that he is creating too many threads, I gave a straight answer. Learning's up to him.Florio
M
3

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.

Marking answered 3/12, 2015 at 8:12 Comment(2)
While that is a good suggestion, look at the source code to find out how threadNum is initialized. I think, that is part of OP's problem.Partlow
@Partlow while this might be part of problem the point about multiple thread pools certainly is. The effect of adding the sleep() also hints at this since it allows the old executors to be cleaned up before creating new ones.Marking

© 2022 - 2024 — McMap. All rights reserved.