Socket BufferedReader.readLine() beenden ohne den Stream zu closen

Blackhole16

Bekanntes Mitglied
Liebe com,

Mal eine Frage, zu der es zwar viele Antworten im netz gibt, mir aber keine hilft:

Wie kann ich einen Thread mit Laufendem BufferedReader.readLine() beenden, sodass auch das readLine() SOFORT unterbrochen wird, ohne jedoch den Stream zu closen?

Hintergrund:
Ich habe ein kleines Spiel geschriben, zu dem ich nun einen Server schreibe. Ich habe erst einmal ein Chatserver geschrieben, über den man auch einen Kampf eröffnen kann. Dazu übergebe ich die I/O-Streams, über die dann die Daten gesendet werden.

Nun ist es leider so, dass der Thread von der ChatServerConnection nicht richtig beendet wird, da bei immernoch auf in.readLine() gewartet wird, bevor sowohl mit Thread.stop als auch mit Thread.interrupt RICHTIG beendet wird.

Dadurch wird die nächste Zeile vom Clienten immernoch an diesen Thread geleitet und der FightThread bekommt nurnoch einen leeren String und nicht die für ihn bestimmten Daten.

Nun habe ich über google erfahren, dass man mit Socket.shutdownInput() genau dies beenden kann, nur leider wird damit der ganze Stram mit EOS geclosed, was ich ja nicht möchte

Ich habe es bisher (sehr unschön) so gelöst, dass ich einfach zum Beginn vor irgendwelchen Berechnungen des Kampfes "abc" sende, damit der ChatThread beendet wird und beim eigentlichen Spielserver leere Strings ignoriere.

Wie kann ich dies eleganter lösen?

mfg
BH16
 
C

Conventions

Gast
Thread.stop() sollte man auf keinen Fall callen -> API-Doc lesen !
Thread.interrupt() ist da schon ETWAS eleganter, sollte man aber auch nur verwenden wenn man einen Thread.UncaughtExceptionHandler verwendet. Wenn dieser nicht gesetzt ist wird der DefaultHandler genutzt der den Thread ähnlich wie stop() "killt". Ist aber auch noch immer nicht "sauber".

Sauber wird ein Thread beendet in dem er an wichtigen Stellen auf ein Flag prüft (bei "endless"-loops im loop-header) und dann selbst dafür sorgt das alles sauber aufgeräumt und run() z.B. mit return; verlassen wird.

Problematisch wird es jetzt allerdings mit so ziemlich allen blocking-methods. Die meisten führen I/O-OPs, es gibt aber noch ein paar andere (und natürlich deadlocks). Um jetzt eine solche blocking-(I/O)-method "sauber" zu "killen" muss man deren lock lösen, also das Ereignis auslösen das die entsprechende Methode returned. Fast alle können aber nur durch native Ereignisse ausgelöst werden da die meisten blocking-(I/O)-methods an eine native-method delegieren.
Wenn man mit Sockets arbeitet ist das relativ einfach : das Gegenüber dazu bringen irgendwas zu senden. Natürlich könnte man jetzt auch mit JNI was basteln was dann in den Stack hooked und dann das Ereignis auslöst, aber ich denke das würde hier zu weit gehen.

Wenn du es doch lieber mit einem "gewaltsamen kill" lösen willst/musst kann man immer noch die blocking-method in ihren eigenen Thread auslagern und diesen dann mit Thread.interrupt() "killen". So würde dann der eigentlichen ClientHanlder-Thread nur aus dem read() returnen und könnte alles sauber aufräumen. Dazu würde ich mit join()/wait() und notify() arbeiten. Auch wenn das immer noch nicht so richtig sauber wäre wäre es dennoch eine sehr "elegante" Art. Wie allerdings beim spezifischen Problem best-pratice wäre hängt denke ich mal vom Fall selbst ab. Man kann ja nicht etwas was man z.B. für Socket-Streams nutzt auch auf File-Streams anwenden (zumindest nicht ohne mit JNI/JNA die OS-API zu manipulieren).

An sich ist also deine aktuelle Vorgehensweise schon ganz gut da du "normal" aus dem read() "springst". Alles andere wäre nämlich falsch/ungünstig/unsauber wenn es nicht zu kompliziert werden soll.
 

HoaX

Top Contributor
Thread.interrupt() ist da schon ETWAS eleganter, sollte man aber auch nur verwenden wenn man einen Thread.UncaughtExceptionHandler verwendet. Wenn dieser nicht gesetzt ist wird der DefaultHandler genutzt der den Thread ähnlich wie stop() "killt". Ist aber auch noch immer nicht "sauber"

Alles was von interrupt() unterbrochen wird schmeißt eigentlich auch eine Exception die man abfangen muss. Und egal ob man einen neuen UncaughtExceptionHandler nutzt oder nicht: Durch die Exception, welche dieser behandelt, wurde die run()-Methode verlassen -> Thread wird beendet.
 

FArt

Top Contributor
Thread#interrupt und Thread#isInterrupted ist das Flag, das man somit nicht extra einführen muss. Der Vorteil ist auch, dass damit ein Thread, der gerade blockiert (z.B. Thread#sleep, Object#wait oder eine Synchronisation, leider nicht in IO-Operationen) ebenfalls unterbrochen wird. Sonst muss man halt das Flag abfragen.

Achtung: auslesen setzt das Flag zurück...
 
S

SlaterB

Gast
die Erläuterungen im ersten Posting sind mir nicht ganz eindeutig, aber nur so als Idee eingeworfen:
für jede Ressource, aus der gelesen wird, ein Extra-Lese-Thread A,
ein anderer Thread B kann sich um die Hauptarbeit kümmern, immer aktiv sein, ab und zu vorbeischauen ob A neue gelesene Daten bereit gestellt hat,
direkte Reaktion wäre vielleicht schöner, kann man ja immer noch mit wait/ notify, welches für B unterbrochen werden kann, einbauen

auf jeden Fall gilt, dass es unsinnig ist, A abzubrechen ohne die Ressource zu schließen,
der einzige Grund sie nicht zu schließen ist doch wohl weiter aus der Ressource zu lesen,
das kann genausogut A endlos machen, niemand sonst wird dort erfolgreicher sein,
also A solange belassen bis die Ressource tatsächlich auch mit geschlossen werden kann da nicht mehr benötigt
 

Mujahiddin

Top Contributor
Thread#interrupt und Thread#isInterrupted ist das Flag, das man somit nicht extra einführen muss. Der Vorteil ist auch, dass damit ein Thread, der gerade blockiert (z.B. Thread#sleep, Object#wait oder eine Synchronisation, leider nicht in IO-Operationen) ebenfalls unterbrochen wird. Sonst muss man halt das Flag abfragen.

Achtung: auslesen setzt das Flag zurück...

Nicht ganz,
bei
Code:
Thread#isInterrupted
bleibt der Status unberührt - bei
Code:
Thread.interrupted()
wird der Status zurückgesetzt.

Allerdings finde ich die interrupt Methode ziemlich Gaga... Und ja, bisschen ausprobieren brachte mir folgenden Code, selbst kompilierbar:

Java:
public class A {
	
	public static void main(String... arg) throws Exception {
		Thread t = new Thread( new Runnable() {
			
			public void run() {
				int i= 0;
				while( i++ < 1_000_000 ) // fill some time
					if( i % 100_000 == 0 )
						println( "Hallo. (" + i + ")" );
				try {
					Thread.sleep( 100 );
					println( "Done" ); // Unreachable
				} catch( InterruptedException e ) {
					println( "Interrupted: " + Thread.currentThread().isInterrupted() ); // false
				}
			}
		}, "SomeThread" );
		t.start();
		println( "Started" );
		t.interrupt();
		println( "Interrupted" );
	}
	
	private static void println(String message) {
		System.out.println( Thread.currentThread().getName() + ": " + message );
	}
}

Es wird eine InterruptedException geschmissen aber
Code:
Thread.currentThread().isInterrupted()
liefert
Code:
false
, ebenso wie
Code:
Thread.interrupted()
.
Kann das einer mal erklären?

Also die Ausgabe ist:
Code:
main: Started
main: Interrupted
SomeThread: Hallo. (100000)
SomeThread: Hallo. (200000)
SomeThread: Hallo. (300000)
SomeThread: Hallo. (400000)
SomeThread: Hallo. (500000)
SomeThread: Hallo. (600000)
SomeThread: Hallo. (700000)
SomeThread: Hallo. (800000)
SomeThread: Hallo. (900000)
SomeThread: Hallo. (1000000)
SomeThread: Interrupted: false

Ziemlich dubios.

E:
Habe gefunden, woran's liegt:
Die Methode interrupt(); setzt das Interrupted-Flag des Threads.
Sobald dieser Thread eine Methode wie
Code:
sleep
oder
Code:
join
etc. betritt, wird der Interrupted-Status zurückgesetzt (fragt mich nicht warum) und eine InterruptedException geschmissen.
 
Zuletzt bearbeitet:

FArt

Top Contributor
Nicht ganz,
bei
Code:
Thread#isInterrupted
bleibt der Status unberührt - bei
Code:
Thread.interrupted()
wird der Status zurückgesetzt.

Allerdings finde ich die interrupt Methode ziemlich Gaga... Und ja, bisschen ausprobieren brachte mir folgenden Code, selbst kompilierbar:

Java:
public class A {
	
	public static void main(String... arg) throws Exception {
		Thread t = new Thread( new Runnable() {
			
			public void run() {
				int i= 0;
				while( i++ < 1_000_000 ) // fill some time
					if( i % 100_000 == 0 )
						println( "Hallo. (" + i + ")" );
				try {
					Thread.sleep( 100 );
					println( "Done" ); // Unreachable
				} catch( InterruptedException e ) {
					println( "Interrupted: " + Thread.currentThread().isInterrupted() ); // false
				}
			}
		}, "SomeThread" );
		t.start();
		println( "Started" );
		t.interrupt();
		println( "Interrupted" );
	}
	
	private static void println(String message) {
		System.out.println( Thread.currentThread().getName() + ": " + message );
	}
}

Es wird eine InterruptedException geschmissen aber
Code:
Thread.currentThread().isInterrupted()
liefert
Code:
false
, ebenso wie
Code:
Thread.interrupted()
.
Kann das einer mal erklären?

Also die Ausgabe ist:
Code:
main: Started
main: Interrupted
SomeThread: Hallo. (100000)
SomeThread: Hallo. (200000)
SomeThread: Hallo. (300000)
SomeThread: Hallo. (400000)
SomeThread: Hallo. (500000)
SomeThread: Hallo. (600000)
SomeThread: Hallo. (700000)
SomeThread: Hallo. (800000)
SomeThread: Hallo. (900000)
SomeThread: Hallo. (1000000)
SomeThread: Interrupted: false

Ziemlich dubios.

Ja, ist richtig so.

[JavaSpecialists 056] - Shutting down threads cleanly
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
X Socket [Anfänger] BufferedReader.readLine() lässt sich Zeit Netzwerkprogrammierung 1
A Socket BufferedReader.readLine() blockiert bis ein im Socket OutputStream was gesendet wird ... Netzwerkprogrammierung 9
B Multi-Threaded block bei BufferedReader.readLine() Netzwerkprogrammierung 8
O BufferedReader.readline kommt nicht zurück Netzwerkprogrammierung 7
B BufferedReader.readLine() ließt nicht vollständig ! ? Netzwerkprogrammierung 5
M HTTP URLConnection + BufferedReader killt meine Umlaute Netzwerkprogrammierung 4
x46 byte[] über BufferedReader auslesen Netzwerkprogrammierung 18
C Socket BufferedReader.read(char[] buffer) blockiert unregelmäßig Netzwerkprogrammierung 3
J BufferedReader.ready() wird nicht true Netzwerkprogrammierung 10
V Socket BufferedReader interrupten? Netzwerkprogrammierung 10
S BufferedReader blockiert zu lange Netzwerkprogrammierung 4
P eine BufferedReader für alles ankommende Netzwerkprogrammierung 2
C 2 BufferedReader als Listener pro Socket (NICHT) möglich? Netzwerkprogrammierung 2
E BufferedReader.ready() immer false Netzwerkprogrammierung 8
R Mittels BufferedReader Objekte lesen? Netzwerkprogrammierung 5
AlClemento Sockets -> BufferedReader Problem Netzwerkprogrammierung 2
C Kollision von ObjectInputStream und BufferedReader ? Netzwerkprogrammierung 6
F BufferedReader Socket Netzwerkprogrammierung 2
J Vom BufferedReader lesen -> hängt ohne Fehler,ohne Except Netzwerkprogrammierung 2
D Komischer Fehler Readline() Netzwerkprogrammierung 7
T Bezeichner "end of line" für die Funktion readline Netzwerkprogrammierung 5
D Client Server Problem, Methode readline() löst SocketException "Connection reset" aus Netzwerkprogrammierung 8
0din SMTP Client - readline problem Netzwerkprogrammierung 4
G .readLine() blockt? Netzwerkprogrammierung 3
B Socket - Scanner - readLine(); Netzwerkprogrammierung 2
M Socket und readLine() Netzwerkprogrammierung 4
J readline blockiert? Netzwerkprogrammierung 9
P Problem mit readLine ---- und mit dem connecten Netzwerkprogrammierung 10
E Sockets, readLine() Netzwerkprogrammierung 7
S readline-thread stoppt vorzeitig Netzwerkprogrammierung 6
F Thread "extern" beenden Netzwerkprogrammierung 3
J ServerSocket sauber beenden Netzwerkprogrammierung 3
J Website-Zugriff beenden Netzwerkprogrammierung 11
T Server mit ThreadPool beenden Netzwerkprogrammierung 5
F Netzwerkprogramm sauber beenden Netzwerkprogrammierung 3
T RMI Registry nicht mit beenden. Netzwerkprogrammierung 6
V Multithreaded Server ueber Konsole beenden Netzwerkprogrammierung 6
G Server Thread beenden Netzwerkprogrammierung 16
musiKk Server sauber beenden Netzwerkprogrammierung 6
T select() ohne NIO - oder wie Worker-Thread sauber beenden? Netzwerkprogrammierung 9
TRunKX Threads beenden sich selber? Netzwerkprogrammierung 6
B Mit RMI Server beenden Netzwerkprogrammierung 4
Y server mit endlosse schleife beenden Netzwerkprogrammierung 6
G Prozess beenden auf Unix Netzwerkprogrammierung 11
N Sock will nicht richtig beenden Netzwerkprogrammierung 7

Ähnliche Java Themen


Oben