Dzieje się tak, ponieważ klasa BufferedInputStream
jest przeznaczona do użytku wielowątkowego.
Tutaj widzisz deklarację in
, która jest umieszczona w klasie nadrzędnej FilterInputStream
:
protected volatile InputStream in;
Ponieważ tak jest protected
, jego wartość może zostać zmieniona przez dowolną podklasę FilterInputStream
, w tym BufferedInputStream
i jej podklasy. Ponadto jest zadeklarowana volatile
, co oznacza, że jeśli którykolwiek wątek zmieni wartość zmiennej, ta zmiana zostanie natychmiast odzwierciedlona we wszystkich innych wątkach. Ta kombinacja jest zła, ponieważ oznacza, że klasa BufferedInputStream
nie może kontrolować ani wiedzieć, kiedy in
zostanie zmieniona. W związku z tym wartość można nawet zmienić między sprawdzeniem wartości null a instrukcją return in BufferedInputStream::getInIfOpen
, co skutecznie sprawia, że sprawdzanie wartości null jest bezużyteczne. Odczytując wartość in
tylko raz w celu buforowania jej w zmiennej lokalnej input
, metoda BufferedInputStream::getInIfOpen
jest zabezpieczona przed zmianami z innych wątków, ponieważ zmienne lokalne są zawsze własnością jednego wątku.
Oto przykład w programie BufferedInputStream::close
, który ustawia in
wartość null:
public void close() throws IOException {
byte[] buffer;
while ( (buffer = buf) != null) {
if (bufUpdater.compareAndSet(this, buffer, null)) {
InputStream input = in;
in = null;
if (input != null)
input.close();
return;
}
// Else retry in case a new buf was CASed in fill()
}
}
Jeśli BufferedInputStream::close
jest wywoływana przez inny wątek podczas BufferedInputStream::getInIfOpen
wykonywania, spowodowałoby to sytuację wyścigu opisaną powyżej.
Eclipse
nie można wstrzymać debugera naif
instrukcji. Może być powodem tej zmiennej aliasu. Chciałem tylko to wyrzucić. Oczywiście spekuluję.