0
  1. Ich habe eine Liste von 40000 Datensätze, die in einer for-Schleife verarbeitet werden müssen. Da ich ein Zwei-Prozessor-System habe. Ich habe eine fixedThreadPool wie folgt erstellt:ExecuterService beendet die Verarbeitung eines Threads von zwei

    int threads = Runtime.getRuntime().availableProcessors(); ExecutorService service = Executors.newFixedThreadPool(threads);

  2. und teilte meine ArrayList in zwei Teil-Listen. Für jede dieser Unterlisten habe ich eine Callable erstellt, die die gleiche Funktion ausführt (beinhaltet das Iterieren über die Unterliste und einige Verarbeitungen) und gibt mir ein Objekt Future zurück.

  3. Ich legte diese beiden CallableexecutorServiceObject.submit(callable) mit und fügte hinzu, die zurück Future Objekt in meiner Liste der Future Objekte

Hier ist meine Frage:

ich System.Out.printLn("Processed Item" +item.id) // consider item as the name of reference variable for current iteration

Alles geschrieben war für einige Zeit in Ordnung, und ich konnte sehen, dass zwei Threads simultan arbeiten. Aber nach einiger Zeit hat einer der Threads die Verarbeitung beendet. Nur ein Thread wird ausgeführt. (Ich weiß das, weil ich auf der Konsole sehen kann, dass die ID für Thread 2 nicht mehr gedruckt wird).

Weiß jemand, wie das passiert ist? Ich meine, warum ExecutorService den 2. Thread gestoppt hat.

Vielen Dank für Ihre Hilfe im Voraus.

Hinzufügen von Beispielcode, wie ich vorher getan haben sollte:

public List<Output> processInputs(List<Input> inputs) 
     throws InterruptedException, ExecutionException { 

    int threads = Runtime.getRuntime().availableProcessors(); 
    ExecutorService service = Executors.newFixedThreadPool(threads); 

    List<Future<Output>> futures = new ArrayList<Future<Output>>(); 
    for (final Input input : inputs) { 
     Callable<Output> callable = new Callable<Output>() { 
      public Output call() throws Exception { 
       Output output = new Output(); 
       // process your input here and compute the output 
       return output; 
      } 
     }; 
     futures.add(service.submit(callable)); 
    } 

    service.shutdown(); 

    List<Output> outputs = new ArrayList<Output>(); 
    for (Future<Output> future : futures) { 
     outputs.add(future.get()); 
    } 
    return outputs; 
+0

Bitte bearbeiten Sie Ihre Frage, um den entsprechenden Code in Ihr Programm aufzunehmen. Im Idealfall sollten Sie ein [mcve] einschließen, das das Problem reproduziert. – Kenster

+0

Das kann nicht wirklich gestoppt werden. Es kann im Wartezustand sein. Überprüfen Sie die run-Methode des nicht funktionierenden Threads und sehen Sie, welche Zeile zuletzt ausgeführt wurde. – pikrut

+0

@pikrut Ich habe 'Callable' verwendet, also gibt es keine run() Methode. Zweitens wird das Callable in einer for-Schleife erzeugt (1 für 1 Unterliste aufrufbar). Das bedeutet, dass die Aufrufmethode für beide Unterlisten gleich ist. – Aman

Antwort

1

Alles war für einige Zeit in Ordnung und ich kann zwei Threads gleichzeitig sehen arbeiten. Aber nach einiger Zeit hat einer der Threads die Verarbeitung beendet. Nur ein Thread wird ausgeführt. (Ich weiß das, weil ich auf der Konsole sehen kann, dass die ID für Thread 2 nicht mehr gedruckt wird).

Ich vermute, dass Ihr Verarbeitungsthread eine Ausnahme ausgelöst hat. Die Future.get() Methode kann ExecutionException"if the computation threw an exception" werfen.

// the following might throw an exception if the background job threw 
outputs.add(future.get()); 

Wenn es eine NPE, eine IOException usw. geworfen von Ihrem „verarbeiten Sie Ihre Eingabe“ Code dann diese Ausnahme von den Callable und gespeichert in den Future geworfen wird, so kann sie durch die get() Methode geworfen werden, sondern eingewickelt in ExecutionException. Dies ist nützlich, damit der Thread, der wartet, die Ausnahme, die vom Hintergrundthread ausgelöst wird, abrufen und behandeln (protokollieren usw.) kann.

Statt nur mit Ihrem processInputs(...) Methode die Ausnahme an den Aufrufer werfen, wo es könnte verloren gehen immer, ich so etwas wie die folgenden in Ihrer while Schleife tun würde:

try { 
    outputs.add(future.get()); 
} catch (InterruptedException ie) { 
    // always a good pattern if the thread that is waiting was interrupted 
    Thread.currentThread().interrupt(); 
    return; 
} catch (ExecutionException ee) { 
    // somehow log the error 
    logger.error("Computation failed to process", ee); 
    // now continue and get the next future in the list 
} 

Wenn Sie nicht fangen und richtig behandeln, dass ExecutionException dann die Verarbeitung Ausnahme wird auch den Thread, der processInputs(...) ruft abbrechen.

+0

Sie haben absolut Recht, ich habe eine ExecutionException auf get() -Methode. Ich habe bereits diese zwei Ausnahmen eingefangen und ich drucke den Stack-Trace auf meiner Konsole. Ist es sinnvoll, die Daten von Thread 1 erneut zu verarbeiten und die Ausgabe zu erhalten? Oder soll ich das Programm einfach neu starten und schauen, ob die Ausnahme noch einmal ausgelöst wird? Ich meine, kann ich etwas besser machen, als den Fehler in meinem Code für solche Fälle zu protokollieren? – Aman

+0

Nicht sicher @Aman. Es hängt davon ab, was Sie tun. Wenn Ihre Verarbeitungsmethode möglicherweise ein zweites Mal funktioniert, können Sie es erneut versuchen. Ich denke, Sie müssen verstehen, warum die Ausnahme passiert und ob eine Wiederholung sinnvoll ist. – Gray

+0

okay, ich werde überprüfen. Danke für die Erklärung, ich akzeptiere deine Antwort. Ich erhalte diese Ausnahme : java.util.concurrent.ExecutionException: org.apache.openjpa.util.StoreException: Erschöpfte Resultset \t \t auf Java. util.concurrent.FutureTask $ Sync.innerGet (FutureTask.java:233) \t bei java.util.concurrent.FutureTask.get (FutureTask.java:94) – Aman

Verwandte Themen