When I read the source code from java.io.BufferedInputStream.getInIfOpen()
, I am confused about why it wrote code like this:
/**
* 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;
}
Why does it use the alias instead of use the field variable in
directly like below:
/**
* 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;
}
Can someone give a reasonable explanation?
If you look at this code out of context there is no good explanation for that "alias". It is simply redundant code or poor code style.
But the context is that BufferedInputStream
is a class that can be subclassed, and that it needs to work in a multi-threaded context.
The clue is that in
is declared in FilterInputStream
is protected volatile
. That means that there is a chance that a subclass could reach in and assign null
to in
. Given that possibility, the "alias" is actually there to prevent a race condition.
Consider the code without the "alias"
private InputStream getInIfOpen() throws IOException {
if (in == null)
throw new IOException("Stream closed");
return in;
}
getInIfOpen()
in == null
and sees that in
is not null
.null
to in
.return in
. Which returns null
because a
is a volatile
.The "alias" prevents this. Now in
is read just once by thread A. If thread B assigns null
after thread A has in
it doesn't matter. Thread A will either throw an exception or return a (guaranteed) non-null value.