6.7. CompletionService

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

6.7. CompletionService
Hallo zusammen!

Kurze Frage:
Ist es erlaubt/sinnvoll, die im Konstruktor erstellten Worker-Threads gleich mittels workers[x].start() zu starten?
Oder soll das starten der Threads an einer andere Stelle erfolgen?

Vielen Dank! :slight_smile:


Es ist auf jeden Fall sinnvoll, die Threads im Konstruktor zu starten. Ansonsten müsstest du dich darum in der [m]submit()[/m]-Methode kümmern, was bestenfalls aufwändig und hässlich wäre.


Okay, ich hab’s jetzt hinbekommen und lokal laufen die Test-Cases durch.
Beim Hochladen im EST bekomme ich ein Ausrufezeichen “error in given test case”.
Laufen da andere Test-Cases drüber? Wenn bei mir lokal alles mit grünem Haken beendet wird, dann müsste das doch im EST auch so sein, oder? :stuck_out_tongue:


EDIT: Sorry für den Doppelpost!


Sollte so sein. Der Test dauert bei dir länger als 1s, deswegen gibt es einen Timeout Error.
Ich schau mal woran es liegt.


Ist bestimmt wieder irgendetwas Doofes, was ich einfach nicht sehe… :stuck_out_tongue:

Vielen Dank schon einmal!


Ich habe eine Frage bezueglich FutureTask.
In der API steht zur [m]run()[/m]-Methode: “Sets this Future to the result of its computation unless it has been cancelled.” Angenommmen, man hat folgende Situation:

FutureTask<V> tmp = new FutureTask<V>(callableObj);
tmp.run();
System.out.println(tmp.toString());

Ich wuerde gerne wissen, ob Zeile 3 erst bearbeitet wird, wenn Zeile 2 fertig abgearbeitet wurde oder ob Zeile 2 nur in Auftrag gegeben wird und man in Zeile 3 dann auf das nicht fertig berechnete tmp zugreift?
Ich komme langsam etwas durcheinander…


[m]run()[/m] führt die [m]call()[/m]-Methode des übergebenen Callable-Objekts aus, nimmt dessen Rückgabewert und verpackt diesen im FutureTask-Objekt (dieser kann nun mittels [m]get()[/m] erhalten werden). Das heißt, dass [m]run()[/m] erst zurückkehrt, wenn die Berechnung in [m]call()[/m] auch sicher abgeschlossen ist. Mit anderen Worten: [m]run()[/m] arbeitet auch beim FutureTask rein sequentiell.


EDIT: Deleted post


Ich komm mit Future nicht ganz zurecht.

Soweit ich das verstehe, für ich eine Berechnung mit: [m]V result = task.call()[/m] aus.
Dieses [m]result[/m] kann ich dann aber nicht in [m]public Future take() throws InterruptedException[/m] zurückgeben, da hier ein [m]Future[/m] verlangt ist. Ein cast geht immer schief :confused:

Wie mach ich das richtig? :>


Die einfachste Variante ist es, einfach überall [m]FutureTask[/m] zu verwenden. Dies ist ein Wrapper zwischen einem Future-Objekt und einem Callable-Objekt. Ein FutureTask kannst du dir also quasi gleichzeitig als Future wie auch als Callable vorstellen. D.h. du kannst einen FutureTask ausführen (mit der run-Methode) wie ein Callable und kannst ihn wie ein Future behandeln (und auch als solches zurückgeben) und mit get() auf Ergebnisse und somit dessen Ausführung warten. Wenn du für ein Callable ein FutureTask-Objekt erstellst, dann erstellst du sozusagen für dieses Callable auch das entsprechende Future-Objekt, in dem automatisch das Ergebnis gespeichert wird, wenn die run-Methode erfolgreich ausgeführt wurde.

Du musst also nur diesen FutureTask als Ergebnis zurückliefern und der Nutzer wird durch einen Aufruf von get genau das Ergebnis des zugehörigen Tasks erhalten, sobald der Task verarbeitet wurde.


Ich habe mich an der f) versucht und es funktioniert noch nicht ganz. Also probiere ich gerade den Fehler zu finden, indem ich [m]testSubmitShutdownAndTake()[/m] nachvollziehen moechte.
Es werden 10 Callables in den FixedThreadCompletionService submittet. Dann wird der Service heruntergefahren. Nun soll 10 mal [m]take()[/m] aufgerufen werden. Zu dieser Stelle habe ich eine Frage:
Angenommen, es werden 3 von 10 take()s ausgefuehrt und dann gilt [m]terminated == true[/m], da sich der letzte Thread beendet hat. Angenommen, es befinden sich in diesem Moment keine Aufrufer in take(), dann werden 0 [m]poisonpills[/m] hinzugefuegt. Wenn nun ein viertes mal take() aufgerufen wird, soll ja anscheinend nicht [m]null[/m] returned werden. Aber was muss ich tun?
In der f) steht: “Sorgen Sie dafür, dass take nicht mehr blockiert, sobald sich der letzte Thread beendet hat (terminated == true)”. Was ist damit genau gemeint, wenn nicht gewollt ist, dass [m]null[/m] returned wird?
Ich stehe etwas auf dem Schlauch…

EDIT: Oder soll man ueberpruefen, ob die Wartschlange mit den fertig bearbeiteten Auftraegen leer ist, falls [m]terminated == true[/m], und nur wenn sie leer ist, [m]null[/m] returnen, und ansonsten das Element, dass noch in der Warteschlange ist? Denn so wuerde [m]take()[/m] nicht mehr blockieren.

EDIT2: Nun laufen die Testfaelle richtig und ich habe auch einen gruenen Haken. Trotzdem wuerde mich interessieren, ob es so gedacht war.


wie lang sollten denn die tests ungefähr laufen?
sind 13s zu lang?


Was ist, wenn take() aufgerufen wird, nachdem der terminationHandler fertig ist?
Dann gibt es ja für diesen speziellen Aufrufer keine poisonpill in der queue…


@m0 bei mir dauert es auch ziemlich genau 13s:
1,125s+6,111s+0,000s+6.001s = 13.237

Ist bei euch auch ungefähr so die verteilung?


Hallo allerseits,
habe das Problem, dass alle Testcases bei mir zwar durchlaufen, ich aber in est ein Ausrufezeichen bekomme. Könnte es an den Wettlaufbedingungen liegen? Kanns mir nicht anders erkären, hab aber auch nicht wirklich ne Idee was da schief laufen soll. An shutdown kanns eigentlich nich liegen aber möglicherweise hab ich in take was übersehen. Hatte jemand zufällig das gleiche Problem?


In der Aufgabenstellung steht doch, dass take() nicht mehr blockieren soll, wenn terminationHandler() aufgerufen wurde. Das heißt, dass sich take() dann wie poll() verhalten soll.


Noch eine Frage zu den PoisonPills:

Kann ich das selbe Objekt mehrmals der LinkedBlockingQueue hinzufuegen? Ich kann ja nicht mehrere poisonpills erstellen… oder?

Und: Kann ich auf poisonpill einfach mit (bla == poisonpill) pruefen oder brauch ich .equals()?

Testcases laufen auf jedenfall durch, hoffe d.h. die zwei Sachen oben passen bei mir :slight_smile:


Ja, eine LinkedBlockingQueue kann ein Element mehrfach enthalten. Daher kannst du die poisonpill auch mehrfach einfügen. Da du ja nur eine poisonpill hast, kannst du hier auch einfach einen Referenzvergleich (obj == poisonpill) durchführen.

1 Like