6.7. CompletionService


Mit welcher Abbruchbedingung arbeitet ihr in der doWork()? Ich nutze derzeit (shutdown && queue.isEmpty()) in einer while(true) Schleife mit entsprechendem break, allerdings beendet diese Schleife das Ganze zu früh. Mir fällt dazu leider auch keine Alternative ein. :confused:


habs eigentlich genauso, while (!(shutdown&&queue.isEmpty())){}. Bei mir funktionierts einwandfrei. Versuch mal statt while(true) mit break meine Version direkt im while-header.


Gut, daran liegt es dann wohl nicht. ich habe den CompletionServiceTest gerade mehrere Male durchlaufen lassen. Teilweise wird bei den Durchläufen bereits nach dem 4. bis n-ten Durchlauf (der Future = cs.take();-for-Schleife in der Klasse CompletionServiceTest) abgebrochen, teilweise läuft er aber auch 10x durch und ruft den terminationHandler gar nicht erst auf.

Weitere Problemmöglichkeit: Ich sehe es schon richtig, dass ich die workers ganz einfach in einer For-Schleife und mit workers[n] = new Worker(threads) initialisiere? Habe vorher jeweils mit der Schleifenvariable gearbeitet, d.h. quasi ID-like… das war wohl falsch?


Als Argument für die Worker soll nicht eine ID übergeben werden, sondern die Anzahl der Arbeiterthreads. Diese wird benötigt, um im Thread die Anzahl der schon beendeten Threads zu zählen, so dass der letzte Thread, der sich beendet, terminationHandler() aufrufen kann.


Okay, daran lag es sowie an dem Vergleich der poisonpill (equals funktioniert hier offenbar aus irgendwelchen Gründen nicht). Jetzt hänge ich noch an der testSubmitShutdownAndTakemultipleThreads: Alle vier threads versuchen bei mir, ein Element zu entnehmen. Es wird aber ja nur durch den letzten Thread (ID=3) ein Element hineingegeben. Entsprechend warten drei von vier Threads weiterhin endlos auf Arbeitspakete. Diese sollen entsprechend die PoisonPills sein - durch shutdown wird aber, wenn ich das richtig verstanden habe, lediglich die Variable auf true gesetzt. Der Termination Handler wird hingegen nicht aufgerufen, da c != threads. An der Stelle verstehe ich die Vorgabe aber zugegebenerweise nicht richtig. Wenn nur ein Arbeitspaket im Pool ist, kann schließlich nur ein Thread dieses bearbeiten. Der damit ist c = 1, c kann aber niemals 4 sein, da es ja nur ien Arbeitspaket gibt - schlussfolgernd wird terminationHandler() nie aufgerufen?


Ich weiß nicht, ob ich dein Problem genau verstehe: Aber es kann passieren, dass die Threads sich in take in doWork befinden und auf Arbeitspakete warten, wenn shutdown aufgerufen wird. Im take selbst merken die Threads natürlich nicht, dass sie sich jetzt beenden sollten und dass keine Arbeitspakete mehr kommen werden. Es ist also deine Aufgabe die Threads dazu zu bringen das take zu verlassen und sich dann entsprechend zu beenden ;).

1 Like

Genau daran lag es, bin gerade nach 2,5 Stunden suchen genau darauf gestoßen. Jetzt gibt’s in JUnit den grünen Haken. Vielen Dank :D. Lösung war also, wie schon bereits gesagt: Statt .take nutze ich jetzt .poll; anschlieend wird überprüft ob der Rückgabewert von poll NULL ist, wenn ja, passiert nichts, sonst wird das Paket abgearbeitet.


Hey Leute, nachdem ich mein task in doWork() starte, wie bzw. wo krieg ich meine completed tasks?

FutureTask<V> ft = queue.poll();
ft.run();

die run() von deinem ft führt zu completed tasks, verwechsle die run() nicht mit der von FixedThreadCompletionService. FutureTask hat seine eigene run().

Tipp: eine Queue reicht nicht.


Ja ich habe 2 Schlangen. Aber die run()-Methode hat void als Rückgabetyp. Wie kann ich mein Ergebnis in die zweite Schlange hinzufügen?


Sets this Future to the result of its computation unless it has been cancelled. (FutureTask (Java Platform SE 7 ))


du fügst deinen FutureTask ft in deine 2. queue ein, dafür hast du analog zu poll() eine andere Methode.


ergebnisliste.put(Ergebnis); ?


das FutureTask ist das Ergebnis, aber ja.


Ich mach sowas:

ft.run();
result.put((FutureTask<V>) ft.get());

Dann teste ich und bekomme eine Fehlermeldung:
Exception in thread “Thread-5” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.concurrent.FutureTask
at FixedThreadCompletionService$Worker.doWork(FixedThreadCompletionService.java:39)
at FixedThreadCompletionService$Worker.run(FixedThreadCompletionService.java:60)


ich hab kein get() gebraucht, einfach nur das result.put(ft). ft ist doch vom typ FutureTask also müsstest du da nichts casten.
du bekommst ein fehler weil dir get() einen Integer zurückgibt und daraufhin versuchst du ein FutureTask daraus zu machen…

1 Like