6

Ich verwende Threads in meiner Java-Anwendung, um parallel die Daten zu erhalten (mit Netzwerkaufrufen). Ich habe eine Methode (die nicht in einer Thread-Klasse ist), die einen Thread-Pool mit gegebener Größe (10-15 max) erstellt und sie für Netzwerkaufrufe verwendet, und ich rufe diese Methode mehrmals aus einer Schleife.Erstellen zu viele Threads in Java

Wenn ich diese Anwendung auf einem langsamen Computer (3GB RAM, Pentium-IV) ausführen, funktioniert alles gut, aber wenn ich es auf einem iMac (32GB RAM, i7 Prozessor) ausführen, erstellt es zu viele Threads, etwa 2500 manchmal und einen Speicherfehler auswerfen.

Ich vermute, dass JVM die fertigen Threads nicht zurück in den Pool zurückstellt, sobald sie fertig sind, daher werden neue Threads erstellt.

Und sogar auf dem iMac, wenn ich Thread.sleep (1000) halten; in der for-Schleife, die ich oben erwähnt habe, funktioniert alles gut. Erstellen von etwa 900 Threads.

nachfolgenden Code-Proben aus dieser Anwendung sind:

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; 
} 

Wenn ich das obige Verfahren unter Verwendung der unten for-Schleife auf iMac nennen, wirft es Speicherfehler, da seine Gewindegänge etwa 2500 zu schaffen. Aber funktioniert auf der langsameren Maschine gut.

Und mit dem folgenden Code, auf iMac funktioniert es gut mit etwa 900 Threads

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

Wenn ich 1000ms Schlafzeit in der oben für die Schleife zu erhöhen, seine Erstellung nur 30-50 Fäden und die Anwendung funktioniert gut.

Wie kontrolliere ich maximale zulässige Threads in meiner Anwendung. Ich soll maximal 10-15 Threads zu gegebener Zeit erstellen/verwenden, aber Java schafft zu viele.

+1

2500 oder sogar 900 Gewinde ist eine große Sache. Was willst du damit machen? –

+0

siehe dies: http://stackoverflow.com/questions/763579/how-many-threads-can-a-java-vm-support –

+0

Ich sehe nichts wie "Erstellen von etwa 900 Threads". Sie erstellen zuerst einen Executor mit einer Anzahl von Threads, die auf 'locations.size()' festgelegt sind. Anschließend durchlaufen Sie diese Speicherortsammlung und erstellen eine Aufgabe pro Speicherort und fügen diese zum Thread-Pool hinzu.Entweder ist diese Standortgröße viel mehr als Sie dachten, oder Sie erstellen nur 10-15 (max) Aufgaben. Und ... nebenbei ... erstelle den Thread-Pool außerhalb dieses Code-Snippets. – Seelenvirtuose

Antwort

4

Es ist nicht Java, das zu viele Threads erstellt, Sie sind!

Erstellen Sie bei jedem Aufruf einer Funktion keinen Executor. Wenn Sie 100 Sammlungen mit jeweils 100 Elementen haben, werden Sie 10000 Threads erstellen - das ist sehr ressourcenintensiv ... Und sinnlos.

ExecutorService executor = Executors.newFixedThreadPool(threadNum); 

Sie haben höchstwahrscheinlich 8 Cores - erstellen Sie einfach ein Vollstrecker mit 8 Threads und es überall benutzen. Ihr Code wird schneller arbeiten und Ihre App wird weniger, viel weniger Ressourcen verbrauchen.

Machen Sie sich mit dieser code review singleton executor Frage vertraut. Möglicherweise können Sie diese Lösung in Ihrer App verwenden.

+0

Während das ein guter Vorschlag ist, sehen Sie im Quellcode nach, wie 'threadNum' initialisiert wird. Ich denke, das ist Teil des OP-Problems. – Seelenvirtuose

+0

In der Tat, aber die Wurzel des Problems ist nicht zu verstehen, wie man Threads richtig verwendet. Aber da es auf dieser Seite darum geht, Fragen zu beantworten, und selbst der OP vermutet, dass er zu viele Threads erstellt, habe ich eine klare Antwort gegeben. Lernen liegt bei ihm. – Dariusz

3

Mit ExecutorService executor = Executors.newFixedThreadPool(threadNum); erstellen Sie einen neuen Thread-Pool für jeden Aufruf von getValuesForKeyFromMaps. Wenn Ihre keySet also 100 Einträge enthält, erhalten Sie 100 Pools mit jeweils 10-15 Threads. Behalten Sie einen Thread-Pool als Instanz- oder Klassenvariable und verwenden Sie sie bei Bedarf.

+0

Während das ein guter Vorschlag ist, schauen Sie im Quellcode nach, wie 'threadNum' initialisiert wird. Ich denke, das ist Teil des OP-Problems. – Seelenvirtuose

+0

@Seelenvirtuose während dies Teil des Problems sein könnte, ist der Punkt über mehrere Thread-Pools sicherlich. Der Effekt des Hinzufügens von 'sleep()' deutet auch darauf hin, da es erlaubt, die alten Executoren zu bereinigen, bevor neue erstellt werden. –