Hallo zusammen.
Ich habe folgendes Problem: Ich kann zwar in Java einen Thread starten,
aber irgendwie nicht beenden. Er läuft trotz stop(), interrupt() u.ä.
einfach weiter.
Könntet ihr mir helfen?
Hier der gekürzte Code:
Das Innenleben des Threads ist wichtig. Wenn da in der run-Methode
steht:
while(true) {
try {
int i++;
} catch (Exception ex) {
}
}
Läuft das natürlich immer. Die InterruptedException, ausgelöst durch
Thread.interrupt, wird einfach verschluckt und es gibt keinen Grund,
warum die run-Methode zum Ende kommen sollte.
Hi Boris,
ja in der Tat, im Thread selbst ist folgendes geschrieben:
1
publicvoidrun()
2
{
3
4
while(true)
5
{...}
6
}
Das heißt ich frage in der While-Schleife ab, ob ein gewisses Flag
gesetzt wird, welches ich dann über eine Variable von "außen" (über das
Objekt) setze?
Oder wie würde man es am besten machen? Denn die Endlos-Schleife brauche
ich definitiv bis zu dem Zeitpunkt, wo eben der Thread beendet werden
soll.
Danke!
Ahnungsloser schrieb:> test_thread.start();
Macht man eigentlich nur mit Threads die sich selbst beenden.
Für Threads hast du eigentlich 2 verschiedene Anwendungen
1. Du willst eine Arbeit parallelisieren. Dann musst du auch die
Ergebnisse zurückbringen und alles synchronisieren.
Dazu solltest du dir Thread Pools anschauen Package:
java.util.concurrent
2. Du brauchst einen unabhängigen Hintergrundprozess, der undefiniert
lange läuft. Du implementierst dazu eine eigene Klasse die entweder von
Thread erbt oder ein entsprechendes Interface implementiert.
Zusätzlich baust du eine Methode ein, die über ein Flag dem Thread
signalisieren kann dass er sich beenden soll.
In der Hauptschleife des Threads prüfst du regelmäßig auf das Flag und
beendest dann ggf. die Schleife. Gesetzt wird das Flag vom
Hauptprogramm, das den Thread instanziiert und gestartet hat.
Basti schrieb:> Nicht die while schleife ist das Problem, sondern der try/catch block.> Der fängt die Exception ab/weg, die den Thread sonst beenden würde.
Das ist trotzdem die Brachialmethode mit der Brechstange.
Super, danke, das werde ich gleich mal probieren.
Habe jetzt eine public boolean-Variable in meiner Threadklasse
implementiert, die dann als Flag von außen schaltbar sein soll und die
While-Schleife in der Threadklasse beeinflusst.
Jetzt habe ich aber das nächste Problem.
Die Instanziierung erfolgt bei mir über folgenden Befehl:
Die besagte Boolean-Variable liegt in "Failure_Msg_Thread".
Jetzt müsste ich aber ja ein Objekt von "Failure_Msg_Thread" erzeugen,
um auf die Boolean-Variable zuzugreifen.
Wie kann ich das tun, damit ein Bezug zu failure_handling existiert und
somit der richtige Thread beendet wird?
Danke!
Ahnungsloser schrieb:> Jetzt müsste ich aber ja ein Objekt von "Failure_Msg_Thread" erzeugen,> um auf die Boolean-Variable zuzugreifen.
Was denkst du machst du mit:
Ahnungsloser schrieb:> new Failure_Msg_Thread(...)
Also schreib das halt in zwei Zeilen und merk dir das Objekt.
du machst eine liste mit thread objekten, und greifst vom hauptprogramm
aus auf die getter- und setter methoden der threads in der liste zu.
ob die dazu "synchronized" sein müssen (sollten) weiß ich jetzt grad
nicht :/
>Was denkst du machst du mit:
Naja ich übergebe dem Konstruktor von Thread ein Objekt, das
"Failure_Msg_Thread" heißt.
In der Klasse Failure_Msg_Thread ist die besagte Variable, aber ich habe
vom Objekt "failure_handling" keinen Zugriff darauf.
Ein Objekt von "Failure_msg_Thread" habe ich ja quasi nicht.
Oder irre ich?
Ahnungsloser schrieb:> failure_handling = new Thread(new Failure_Msg_Thread(...) )
Sehe ich jetzt erst.
Was soll das?
Ich denke FailureMsgThread() ist abgeleitet von Thread.
Also heisst das
Thread failureHandling = new FailureMsgThread(...);
...
failureHandling.start();
...
// Am Ende:
failureHandling.setEndThread(); // oder wie auch immer du das FLag
setzt
// jetzt noch etwas warten oder prüfen ob der Thread beendet ist
..
Irgendwie fehlen dir alle Grundlagen. Bevor du multithreaded
programmierst solltest du die ersten 5 Kapitel von "Java ist auch eine
Insel" mal durchgelesen und erst mal einfache Programme programmiert
haben.
Und gewöhne dir bitte die Unterstriche ab und benutze die in Java
übliche Notationskonventionen für Methoden, Klassen, Variablen und
Konstanten.
Ach Mist muss natürlich heissen:
FailureMsgThread failureHandling = new FailureMsgThread(...);
heissen, sonst kommst du nicht an die spezifischen Methoden der
abgeleiteten Klasse.
>Thread failureHandling = new FailureMsgThread(...);
Das funktioniert bei mir schon gleich garnicht..es müsste doch wenn dann
>Failure_Msg_Thread failure_handling = new Failure_Msg_Thread
lauten?!
Etwas moderner (ok, das Konzept stammt schon aus Anfang der 90er oder
früher, aber Java hat es spät implementiert) ist es Futures zu
verwenden.
Leider ist die JavaDoc dafür ziemliche mies
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html
und sowohl die Implementierung also auch die Beispiele die man in
diversen Tutorien findet verschleiern die Idee mehr als das sie die
Vorteile zeigen.
Eigentlich geht es um die Idee der Active Objects. Das ist eine Technik
um Concurrent Programme zu strukturieren. Ein Future ist dabei nur ein
Hilfsmittel, ein Versprechen (ein Platzhalter) auf ein Ergebnis, das ein
(Active) Object irgendwann mal liefert. Ein Active Object ist ein
Objekt, das intern einen oder mehrere Threads verwendet, aber seine
Außenwelt nicht mit Thread-Details behelligt. D.h. es enkapsuliert
Threads und regelt alle Thread-Operationen wie Synchronisation,
Schedulling alleine. Im Gegensatz zu normalen Threads läuft ein Thread
nicht wild über Objektgrenzen hinweg (wenn man es nicht verpfuscht) und
Thread-Code ist nicht über die ganze Codebasis verschmiert.
Damit verbunden ist die Idee des asynchronen Methodenaufrufs (hat Booch
glaube ich schon in den 80ern in seine OO-Methode). Methoden liefern
nicht sofort ein Ergebnis, sonder verhalten sich asynchron. Sie liefern
nur ein Versprechen auf ein Ergebnis (ein Future). Der Aufrufer kann das
eigentliche Ergebnis vom Future erfragen wenn er es benötigt. Das sollte
der Aufrufer so spät wie möglich machen, um dem Active Object genug Zeit
zur Berechnung zu geben. In der Zwischenzeit kann der Aufrufer etwas
anderes machen.
Das Konzept sieht so aus (Code sieht durch die println()s schlimmer aus
als er ist):
Jay schrieb:> Etwas moderner (ok, das Konzept stammt schon aus Anfang der 90er oder> früher, aber Java hat es spät implementiert) ist es Futures zu> verwenden.
Macht nur Sinn, wenn man mit Threads Berechnungen parallelsieren will
und die Ergebnisse braucht.
Für einen Thread der unbestimmt lange als "Daemon Thread" neben dem
Hauptprogramm läuft und erst mal unabhängig werkelt ist das Unsinn.
Ausserdem hab ich daruf oben schon hingewiesen
Der Andere schrieb:> Dazu solltest du dir Thread Pools anschauen Package:> java.util.concurrent
Aber der TO kann ja nicht mal eine Klasse von Thread ableiten und die
dann starten. Also sind Future Callable und Threadpools für ihn soch so
weit weg wie der Mond.
Ahnungsloser schrieb:> Das funktioniert bei mir schon gleich garnicht..es müsste doch wenn dann>>Failure_Msg_Thread failure_handling = new Failure_Msg_Thread> lauten?!
Siehe meine Korrekur.
Aber auch hier: Grundlagen was ist Polymorphie
https://de.wikipedia.org/wiki/Objektorientierung#Polymorphie
Da wird doch mit Kanonen auf Spatzen geschossen.
Es muss doch auch mit meinem Code gehen.
Wenn ich ein Objekt von "Failure_Msg_Thread" erzeuge, läuft der Thread
zwar, aber das Main-Programm hängt sich auf. (Warum auch immer..)
Immerhin hat der Thread bei der "falschen" Notation funktioniert:
>failure_handling = new Thread(new Failure_Msg_Thread
Er lässt sich nur nicht beenden.
Ich verstehe es nicht :(
Der Andere schrieb:> Macht nur Sinn, wenn man mit Threads Berechnungen parallelsieren will> und die Ergebnisse braucht.
Was er ja wohl will (den Boolean den er haben will). Aber egal, alles
nicht mein Problem.
Jay schrieb:> Was er ja wohl will (den Boolean den er haben will). Aber egal, alles> nicht mein Problem.
Die boolean Variable ist zu Signalisierung dass der Thread sich beenden
soll.
Dein Problem ist hier eher das verstehende Lesen :-)
Ahnungsloser schrieb:> Ich verstehe es nicht :(
Dann backe erst mal kleinere Brötchen bis du Klassen und Objekte und
deren Instanziierung verstanden hast.
Sorry, aber ich muss jetzt mal wieder was arbeiten.
Der Andere schrieb:> Dein Problem ist hier eher das verstehende Lesen :-)
Dein Problem ist, dass du ein Arsch bist.
> Sorry, aber ich muss jetzt mal wieder was arbeiten.
Ah, jetzt verschwinden, nachdem du alle Weggebissen hast. Sehr
sympathisch.
>Dann backe erst mal kleinere Brötchen bis du Klassen und Objekte und>deren Instanziierung verstanden hast.
Das habe ich. Sorry für meinen Fehler vorhin...
Sobald ich FailureMsgThread instanziiere und <OBJEKT>.run(); ausführe,
läuft zwar der Thread bis zum St.Nimmerleinstag, aber das Main-Programm
hängt sich auf.
Ich schicke jetzt nochmal meinen Code, in der Hoffnung, dass mir jemand
hilft und mich nicht fertig macht, weil ich ja so ein dummer Anfänger
bin.
Thread:
Ahnungsloser schrieb:> SwingWorker? noch nie gehört.
Dann ist es jetzt Zeit, sich damit anzufreunden, wenn du eh Swing
machst.
> Das Problem ist, dass der Thread einwandfrei funktioniert: Er lässt sich> nur nicht schließen/beenden!!!!
Nein, das Problem ist, dass du das Problem nicht kennst, du meinst eine
Lösung (Thread, wobei, nichtmal das, du implementierst ja "Runnable") zu
kennen.
Das tritt hier im Forum sehr oft auf, die Leute kommen mit Lösungen
und nicht mit Problemen.
Dein Problem ist:
Du hast eine Swing-Anwendung und willst irgendwas abbrechbares im
Hintergrund machen, das sporadisch deine Oberfläche aktualieren soll.
Die Lösung dazu:
SwingWorker
Ok..dann werde ich mich heute Abend entsprechend einlesen und bedanke
mich schonmal für das Stichwort! :)
Ich melde mich, falls Probleme auftreten.
Grüße u. Danke!
Ahnungsloser schrieb:> Sobald ich FailureMsgThread instanziiere und <OBJEKT>.run(); ausführe,
In meinem oben angegebenen Link zum Tutorial wird dir erklärt warum du
start() und nicht run() aufrufen sollst. run() läuft nämlich im
Hauptthread und nicht in einem neuen, und da die run() Methode eben
wartet bis sie ein zeichen zum Beenden kriegt, das sie aber nie kriegen
kann weil das Programm ja jetzt nicht weiterlaufen kann, hängt das
Programm.
Nochmal: Ohne Grundlagen hangelst du dich nur von einem Problem zum
anderen.
Das ist doch wieder mal "programming by copy paste".
Jay schrieb:> Der Andere schrieb:>> Dein Problem ist hier eher das verstehende Lesen :-)>> Dein Problem ist, dass du ein Arsch bist.
Was du bist zeigst du ganz klar, Unfug schreiben, keine Argumente, dafür
Beleidigungen.
Jay schrieb:> Ah, jetzt verschwinden, nachdem du alle Weggebissen hast. Sehr> sympathisch.
Im Gegensatz zu dir muss ich arbeiten und verdiene damit Geld. Der
Wadenbeisser passt besser zu dir. Und ich habe wenigstens konkret
geholfen statt 100 Zeilen viel zu komplexen und nicht zum Problem
passenden Code einfach einem Anfänger vorzuwerfen.
Ob du selbst den Code verstehst oder nur irgendwo rauskopiert hast weist
nur du (hoffentlich).
Ahnungsloser schrieb:> läuft zwar der Thread bis zum St.Nimmerleinstag
Ist kein Thread, heißt nur so.
> aber das Main-Programm> hängt sich auf.
Tut es nicht. Es führt die run-Methode Deines Failure_Msg_Thread-Objekts
aus.
Du erstellst gar keinen Thread und startest auch keinen.
Ein Runnable fängt nicht von selbst an, in einem eigenen Thread zu
laufen, indem man seine run-Methode aufruft.
Gestern habe ich noch bis 1 Uhr diesen SwingWorker versucht zu nutzen.
Leider mit noch weniger Erfolg.
Ich nahm die alten Anweisungen der Klasse Failure_Msg_Thread und
kopierte sie in die "execute()"-Methode.
Die "DoinBackground"-Methode funktionierte garnicht, bei der
"execute"-Methode habe ich seither den Fehler:
"Cannot override the final method from Swingworker<Integer,Integer>"
Grundgerüst der ThreadKlasse sieht so aus:
Im Hauptprogramm rufe ich das Ganze dann mit ".execute()" auf.
Funktioniert wiegesagt ja nicht, da ein Fehler in der Threadklasse
vorliegt, den ich nicht zu beheben weiß...
Wisst ihr weiter?
Danke.
Nach meinem Dafürhalten sollte ja jetzt beim Ausführen von
<OBJEKT>.setStop() das entsprechende Stop-Flag gesetzt werden, damit das
Ding anhält und nicht mehr ewig weiterläuft.
TUT ES ABER WIEDER NICHT!
So rufe ich es auf:
1
if(e.getSource()==btn_Stop)
2
{
3
4
Failure_Msg_Thread.setStop();
5
}
Bin jetzt wirklich mit meinem Latein am Ende und hoffe nun auf eure
Hilfe!
Gruß
Ahnungsloser schrieb:> Die "DoinBackground"-Methode funktionierte garnicht, bei der> "execute"-Methode habe ich seither den Fehler:
Öhm, wie kommst du auf die Idee execute zu überschreiben? Das ist
absolut nicht nötig.
Dein Hintergrundzeugs muss natürlich in doInBackground() laufen, die
Methode heisst ja schon so...
Dieses ganze Gedöns mit dem boolean kannst dir auch sparen, du kannst
den laufenden Worker jederzeit mit cancel() abbrechen (das steht auch in
dem verlinkten Beispiel).
Deine JLabel versorgst du aus der Methode process (die du, vielleicht
etwas ungewohnt, über publish aufrufst):
1
@Override
2
protected void process(List<String> chunks) {
3
// Messages received from the doInBackground() (when invoking the publish() method)
4
}
Warum du jetzt mit SwingWorker<Integer, Integer> arbeitest und nicht mit
SwingWorker<Void, Void> oder gar SwingWorker<BigDecimal, String>
solltest du dir auch nochmal durch den Kopf gehen lassen.
Und weil du wahrscheinlich nicht von selber drauf kommst:
Nochmal, schmeiss diesen ganzen boolean-kram raus, getter, setter,
variable, alles.
SwingWorker bietet dir isCancelled() an (die du bitte nicht selber
implementierst).
In deiner doInBackground() steht dann also als erstes:
Hi,
danke für deine Antwort, ich denke meine letzte Antwort hat sich mit
deiner überschnitten.
Ich prüfe nun in meiner Endlosschleife in der Threadklasse folgendes:
Kann es daran liegen, dass ich in "DoInBackground" mit Anweisungen
arbeiten, die exceptions benötigen?
(Öffne darin einen Socket u. diverse Input/Outputstreams)?
Fehler gefunden.
Das Problem lag daran, dass die Instanziierung von "Failure_Msg_Thread"
außerhalb der beiden IF-Anweisungen im Hauptprogramm erfolgte.
So lässt er sich starten, aber NICHT beenden:
1
publicvoidactionPerformed(ActionEvente)
2
{
3
fmt=newFailure_Msg_Thread(..);
4
5
if(e.getSource()==btn_start)
6
{
7
fmt.execute();
8
...
9
}
10
11
if(e.getSource()==btn_stop)
12
{
13
fmt.cancel(true);// wirkungslos!
14
...
15
}
16
}
So aber lässt er sich starten und stoppen:
1
publicvoidactionPerformed(ActionEvente)
2
{
3
4
5
if(e.getSource()==btn_start)
6
{
7
fmt=newFailure_Msg_Thread(..);
8
fmt.execute();
9
...
10
}
11
12
if(e.getSource()==btn_stop)
13
{
14
fmt.cancel(true);// wirkungslos!
15
...
16
}
17
}
Das verstehe ich überhaupt nicht. Aber gut..läuft jetzt.
Gruß
Ahnungsloser schrieb:> Das verstehe ich überhaupt nicht.
Ich überlass dir das mal als Fleissaufgabe.
> Aber gut..läuft jetzt.
Nur wie halt.
Dein Exceptionhandling ist defacto nicht vorhanden.
Einfach
1
protected Void doInBackground() throws Exception
hinzurotzen sorgt zwar dafür, dass dein Code anstandslos compiled, aber
eigentlich macht man das anders.
Schau dass du das in der Schleife sauber abfängst mit multicatch (ein
try, viele catches) und entsprechend passende Meldungen ausgibst und die
Schleife sauber verlässt.
>Ich überlass dir das mal als Fleissaufgabe.
Man kann doch in einer Methode ein Objekt erzeugen.
Das Verhalten müsste doch eigentlich genau andersrum sein, dass die
If-Anweisung von einer anderen If-Anweisung gekapselt ist und ich in der
zweiten If nichtmal das Objekt der ersten sehen dürfte?!
Klar und du hast jedesmal ein neues Objekt erzeugt und dieses dann
angehalten.... aber nicht den Thread der bei einem früheren Aufruf der
ActionPerformed-Methode erzeugt wurde....
Du solltest mal an den Grundlagen arbeiten..
Wenn du dann das mit den Exceptions (incl. aussagekräftigen
Fehlermeldungen und sauberen exits) ausprogrammiert hast, kannst ja auch
mal noch so eine Verriegelung wie in meinem Beispiel einbaun.
Weil: http://imgur.com/vRF9b47
Ahnungsloser schrieb:> Liegt es denn eventuell an ...
Das liegt daran das du erst mal ein paar Grundlagen dir aneignen und
VERSTEHEN solltest! Programmieren ist doch keine Quizshow wo man sich
munter von Frage zu frage "rät" und im Zweifle den Foren-Joker befragt.
Ahnungsloser schrieb:> Bin jetzt wirklich mit meinem Latein am Ende
Latein (oder eine andere Sprache, gilt auch für Programmiersprachen)
lernt man auch nicht dadurch das man sich aus irgendwelchen Büchern
Satzfetzen zusammenkopiert....
Läubi .. schrieb:> Programmieren ist doch keine Quizshow wo man sich> munter von Frage zu frage "rät" und im Zweifle den Foren-Joker befragt.
Jetzt weiß er aber wenigsten, was Backtracking ist, aber nicht, daß man
das nicht für die Entwicklung verwendet.