Wenn ich den Quellcode von lese java.io.BufferedInputStream.getInIfOpen()
, bin ich verwirrt darüber, warum er Code wie diesen geschrieben hat:
/**
* Check to make sure that underlying input stream has not been
* nulled out due to close; if not return it;
*/
private InputStream getInIfOpen() throws IOException {
InputStream input = in;
if (input == null)
throw new IOException("Stream closed");
return input;
}
Warum wird der Alias verwendet, anstatt die Feldvariable in
direkt wie unten zu verwenden:
/**
* Check to make sure that underlying input stream has not been
* nulled out due to close; if not return it;
*/
private InputStream getInIfOpen() throws IOException {
if (in == null)
throw new IOException("Stream closed");
return in;
}
Kann jemand eine vernünftige Erklärung geben?
java
bufferedinputstream
Heilige
quelle
quelle
Eclipse
können Sie einen Debugger für eineif
Anweisung nicht anhalten . Könnte ein Grund für diese Aliasvariable sein. Ich wollte das nur rauswerfen. Ich spekuliere natürlich.if
Aussage wirklich nicht pausieren ?Antworten:
Wenn Sie diesen Code außerhalb des Kontexts betrachten, gibt es keine gute Erklärung für diesen "Alias". Es ist einfach redundanter Code oder schlechter Codestil.
Der Kontext ist jedoch, dass
BufferedInputStream
es sich um eine Klasse handelt, die in Unterklassen unterteilt werden kann und in einem Multithread-Kontext arbeiten muss.Der Hinweis ist, dass in
in
is deklariertFilterInputStream
istprotected volatile
. Das bedeutet , dass eine Chance besteht, dass eine Unterklasse in und assign erreichen konntenull
zuin
. Angesichts dieser Möglichkeit ist der "Alias" tatsächlich vorhanden, um eine Rennbedingung zu verhindern.Betrachten Sie den Code ohne den "Alias"
getInIfOpen()
in == null
und sieht dasin
nichtnull
.null
zuin
.return in
. Was zurückkehrt,null
weila
avolatile
.Der "Alias" verhindert dies. Jetzt
in
wird nur einmal von Thread A gelesen. Wenn Thread Bnull
nach Thread A zuweistin
, spielt dies keine Rolle. Thread A löst entweder eine Ausnahme aus oder gibt einen (garantierten) Wert ungleich Null zurück.quelle
protected
Variablen in einem Multithread-Kontext böse sind.protected
Variablen in unserem Code verwenden sollten, wenn dieser über mehrere Threads verfügt?Dies liegt daran, dass die Klasse
BufferedInputStream
für die Verwendung mit mehreren Threads ausgelegt ist.Hier sehen Sie die Deklaration von
in
, die in die übergeordnete Klasse gestellt wirdFilterInputStream
:Da dies der
protected
Fall ist , kann sein Wert von jeder Unterklasse vonFilterInputStream
einschließlichBufferedInputStream
und seinen Unterklassen geändert werden . Außerdem wird es deklariertvolatile
. Wenn also ein Thread den Wert der Variablen ändert, wird diese Änderung sofort in allen anderen Threads wiedergegeben. Diese Kombination ist schlecht, da die KlasseBufferedInputStream
nicht steuern oder wissen kann, wann siein
geändert wird. Somit kann der Wert sogar zwischen der Prüfung auf Null und der return-Anweisung in geändert werdenBufferedInputStream::getInIfOpen
, wodurch die Prüfung auf Null effektiv unbrauchbar wird. Durch dasin
einmalige Lesen des Werts zum Zwischenspeichern in der lokalen Variableninput
ist die MethodeBufferedInputStream::getInIfOpen
vor Änderungen durch andere Threads geschützt, da lokale Variablen immer einem einzelnen Thread gehören.Es gibt ein Beispiel in
BufferedInputStream::close
, dasin
auf null gesetzt ist:Wenn
BufferedInputStream::close
es von einem anderen Thread aufgerufen wird, währendBufferedInputStream::getInIfOpen
es ausgeführt wird, würde dies zu der oben beschriebenen Race-Bedingung führen.quelle
compareAndSet()
,CAS
usw. im Code und in den Kommentaren. Ich habe auch denBufferedInputStream
Code durchsucht und zahlreichesynchronized
Methoden gefunden. Es ist also für die Verwendung mit mehreren Threads gedacht, obwohl ich es sicher noch nie so verwendet habe. Wie auch immer, ich denke deine Antwort ist richtig!getInIfOpen()
nur vonpublic synchronized
Methoden von aufgerufen wirdBufferedInputStream
.Dies ist ein so kurzer Code, der sich jedoch in einer Umgebung mit mehreren Threads theoretisch
in
direkt nach dem Vergleich ändern kann, sodass die Methode etwas zurückgeben kann, das sie nicht überprüft hat (sie kann zurückkehrennull
und genau das tun, was sie beabsichtigt war) verhindern).quelle
in
könnte zwischen der Zeit ändern Sie die Methode und die Rückgabe des Wertes nennen (in einer Multithread - Umgebung)?in
sich dies jederzeit ändern kann).Ich glaube, das Erfassen der Klassenvariablen
in
in der lokalen Variableninput
soll inkonsistentes Verhalten verhindern, wennin
es während dergetInIfOpen()
Ausführung von einem anderen Thread geändert wird.Beachten Sie, dass der Eigentümer von
in
die übergeordnete Klasse ist und diese nicht als markiertfinal
.Dieses Muster wird in anderen Teilen der Klasse repliziert und scheint eine vernünftige defensive Codierung zu sein.
quelle