Also ich habe einen Musikplayer programmiert, der auch schon recht gut funktioniert. Jedoch hatte er einen Bug: Sobald man ein Lied gestartet hat, ging die CPU-Auslastung auf 100%, als ich pausiert hab war sie immer noch auf 70-80%. Das Problem war, das an 3 Stellen im Code repaint ohne Pause in 3 verschiedenen Threads durchgeführt wurde. Lösung war ein einfaches Thread.sleep();
So, ein Problem was ich gerade behoben hatte, war ganz einfach, das die Threads in einer while-Schleife liefen, solange das Lied spielt. Wenn das Lied vorbei war, wurde die variable false gesetzt und alles sollte gut sein. Wars natürlich nicht, da die Variable wieder true war, bevor die Threads aufgewacht waren. War zwar kein Performance-Problem in dem Sinne (nach 100 liedern und dementsprechend 300 Threads ging die CPU-Auslastung um 1% hoch), aber ich fand das doch recht unschön. Jetzt hab ich das Problem so gelöst, das sobald das Lied vorbei ist, auf allen Threads interrupt(); ausgeführt wird. Die Exception die dabei fliegt, erscheint durch das Printstacktrace ja immer in der Ausgabe. Deswegen die Frage, ob man die nicht einfach ignorieren kann? Mir wurde gesagt nie eine Exception verschlucken, aber in diesem Fall würd ichs doch gerne tun, da sie ja gewollt ist. Oder gibts gar ne andere Möglichkeit einen Thread aufzuwecken, obwohl die sleep-Dauer noch läuft?
Threads sollte man ““üblicherweise”” nicht interrupten. Stattdessen sollte man ein entsprechendes flag setzen, so dass der Thread ganz natürlich ausläuft.
Wenn der Thread irgendwas macht, was nicht durch ein Flag gelöst werden kann (z.B. ein langes wait), dann kann man interrupt aufrufen. Dazu sollte an den ensprechenden Stellen “damit gerechnet” werden, d.h man sollte dann eben nicht einfach ein “e.printStackTrace” irgendwo hinschreiben, sondern an dieser Stelle entsprechend mit der Exception umgehen.
Insgesamt klingt es aber IMHO schon seltsam, wenn du sagst, das drei Threads in Endlosschleifen dauernd repaint() aufrufen … … …
Die Threads fragen die momentane Position vom Lied ab und setzen so die momentane Position ins Label bzw repainten die Progressbar, das damit gemeint. Die Schleife wird beendet wenn das Lied zu ende ist und ein neuer Thread startet. Und ich könnte das ohne das interrupt machen, indem ich in die Schleife, die das nächste Lied abspielt noch ein sleep reinmachen, 1ms länger als der andere Thread. Damit würde es funzen, aber dann merkt man, das er kurz pasiert und genau das will ich vermeiden, deswegen benutze ich das interrupt, um den Thread aus dem sleep zu holen, der andere Thread wartet daraufhin 10ms, was ausreicht damit der andere Thread sich beendet.
Aber ich will einfach nur, das der Thread sich beendet, sobald das Lied ausläuft, egal ob er grad schläft und somit den aktuellen wert nich erfragen kann.
Ok, zugegebenermaßen ist die Frage ein wenig kurz. Ich bin allerdings der Meinung, dass es einige Anwendungsfälle gibt, bei denen ein Interrupt angebracht ist. Ob dieser hier dazu zählt, vermag ich derzeit noch nicht zu beurteilen, weil mir die Konstruktion auch ein wenig merkwürdig vorkommt.
Die Methode, die den Thread interrupted sollte vielleicht in der Klasse liegen, der der Thread gehört, damit das Interruptverhalten gekapselt wird. Außerdem sollte natürlich kein Stacktrace ausgegeben werden, wenn der Interrupt erfolgt.
Aber an und fĂĽr sich finde ich einen Interrupt nicht falsch, zumal die InterruptedException vom Thread#sleep() sowieso gefangen werden muss.
Dieses von Marco erwähnte Running-Flag statt “isInterrupted()” zu verwenden, ist nur ein Behelf für Threads die nicht von anderen abhängig sind oder für Runnables. Ansonsten sollte man schon “interrupt()” verwenden, damit wartende (abhängige) Threads per InterruptedException informiert werden können. Muss man eine InterruptedException innerhalb der “run()”-Methode eines Threads (etwa wegen “Thread.sleep()”, “wait()” oder “join()”) sollte im Catchblock immer “super.interrupt()” aufgerufen werden, weil nicht sichergestellt ist, dass die Exception vom aktuellen Thread kam (deswegen muss sie ja auch gefangen werden). Ansonsten steht bei mir in Catchblöcken von InterruptedExceptions immer ein simples “// dann halt nicht”, wenn nicht noch was anderes zu tun ist. Logging und StackTrace ist bei 'ner InterruptedException jedenfalls nicht nötig, aber wer es sich geben will…
Der zweite Link bestätigt meinen Kenntnisstand zu 100% und sagt keinesfalls aus, dass man Thread#interrupt() vermeiden soll. Im Gegenteil, man soll es verwenden (anstatt Thread#stop()).
Der erste Link scheint nicht nur temporär down zu sein.
Ich sagte oben ja auch nicht, dass man den Interrupt unreflektiert benutzen soll, sondern nach Möglichkeit kapseln oder zumindest das Interruptverhalten im System konsistent sein muss. Natürlich muss man auch die Alternativen (synchronisierte Flags, allgemeine Synchronisierungsklassen) im Hinterkopf haben und dann entscheiden, welche Lösung die eleganteste ist.
*** Edit ***
So, den Artikel vom ersten Link habe ich jetzt auch gelesen (google-Webchache). Und wiederum: dort wird sogar explizit von der Verwendung eines Flags abgeraten, weil der Interrupt bereits die benötigte Funktionalität bietet.
Die Frage von oben bleibt also offen: “Warum (sollte man Threads üblicherweise nicht interrupten)?”
[QUOTE=mymaksimus]das heisst aber wiederum das in einem thread der lange läuft immer eine while true schleife sinnvoll ist oder wie?[/QUOTE]Nö… eine “while(!isInterrupted())”-Schleife.
Auch wenn ich die Exceptions selten direkt behandl (das hat aber was mit eigener Philosphie/Politik am Hut). Es gibt nix schlimmeres als ein unklares verhalten des Programms weil irgend welche Exceptions mit try-catch gefangen wurden, aber die Ausgabe geschluckt wurde.
Vielleicht spielen da ausnahmsweise mehr „subjektive“ Dinge mit rein, als sonst (wenn ich solche pauschal klingenden Empfehlungen gebe). Eine „isRunning“-Flag hat eine klare Semantik, und auf einem Objekt foo.setRunning(false) aufzurufen ist zugänglicher, als sich zu irgendeinem Thread durchzuhanglen, der das Ding gerade ausführt, und auf dem dann interrupt() aufzurufen. Ein weiterer Aspekt, der damit zusammenhängt, ist, dass der Interrupted-Status oft gar nicht und meistens nicht richtig abgefragt und behandelt wird. Meistens sieht man eben
:rolleyes:
Aber tatsächlich ist der einzige halbwegs „technisch fundierte“ Grund, warum man das Interrupted-Flag IMHO nicht sinnvoll verwenden kann, der, dass man (ähnlich wie Spacerat schon angedeutet hat) den Thread oft nicht kennt. Wenn man irgendein Runnable an einen ThreadPoolExecutor schickt, will man ja eigentlich nicht einen der Threads da drin abschießen, sondern lediglich dafür sorgen, dass das Runnable fertig wird.
Aber nicht umsonst stand in meiner Aussage ja „“„üblicherweise“„“, und nicht „„üblicherweise““, „üblicherweise“ oder gar „immer“
[QUOTE=Marco13]Ein weiterer Aspekt, der damit zusammenhängt, ist, dass der Interrupted-Status oft gar nicht und meistens nicht richtig abgefragt und behandelt wird. Meistens sieht man eben
try { something(); }
catch (InterruptedException e) {
// TODO Auto-generated catch-block
}
```[/QUOTE]
Zählt nicht ;-) Dass man viel falsch machen kann, ist auch klar. Ebenso häufig wird man aber auch nicht synchronisierte / volatile isRunning-Flags finden.
[QUOTE=Marco13;67592]Aber tatsächlich ist der einzige halbwegs "technisch fundierte" Grund, warum man das Interrupted-Flag IMHO nicht sinnvoll verwenden kann, der, dass man (ähnlich wie Spacerat schon angedeutet hat) den Thread oft nicht kennt. Wenn man irgendein Runnable an einen ThreadPoolExecutor schickt, will man ja eigentlich nicht einen der Threads da drin abschießen, sondern lediglich dafür sorgen, dass das Runnable fertig wird.[/QUOTE]
Oben habe ich daher von "Kapselung" geschrieben. Wenn man ein ganzes Objekt hat, das Runnable implementiert, kann man dort den Interrupt auslösen lassen (dieses Objekt kann eine Referenz auf den Thread vorhalten).
Und das mit dem ThreadPoolExecutor ist ein ganz schwaches Argument ;-P [japi]Future#cancel(boolean)[/japi]
"
[spoiler]Auch wenn mein Beitrag vielleicht ein bisschen Ketzerisch klingt: ist nicht böse gemeint :o)[/spoiler]
[QUOTE=cmrudolph]dieses Objekt kann eine Referenz auf den Thread vorhalten[/QUOTE]Dann nenne er mir mal die sinvolle Verwendung von „new Thread(new Runnable() {run(){}})“. Wenn das Runnable zur korrekten Funktion den Thread kennen muss, kann man auch gleich immer Thread erweitern. Neenee, dieses Flag hat zumindest in Runnables schon seine Richtigkeit.
Eine anonyme Klasse, die ein isRunning-Flag haben soll? Das wĂĽrde ich definitiv nicht machen.
Um jetzt keine vorschnellen Äußerungen zu tätigen (grad nicht so viel Zeit), gehe ich erstmal noch nicht detaillierter auf die Form der Kapselung, die ich meinte, ein.
Bei einem nicht synchronisierten / volatile isRunning-Flag hat man es selbst versaut, wenn aber in einer verwendeten Lib ein leerer InterruptedException-catch-Block oder auch ein Thread.interrupted() steht, dann haben es „die anderen“ versaut. Ist natürlich besser, wenn es die anderen versaun.
[QUOTE=cmrudolph]Eine anonyme Klasse, die ein isRunning-Flag haben soll? Das würde ich definitiv nicht machen.[/QUOTE]Ich auch nicht. Die war nur anonym, damits in eine Zeile passt. Sollte nur aufzeigen, dass ein Runnable das Thread-Objekt auf dem es läuft gar nicht kennen kann.