问题描述
当我从 java.io.BufferedInputStream.getInIfOpen()
中读取源代码时,我很困惑为什么它编写这样的代码:
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 is it using the alias instead of using 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.
但上下文是 BufferedInputStream
是一个类可以是子类化,并且它需要在多线程上下文中工作。
But the context is that BufferedInputStream
is a class that can be subclassed, and that it needs to work in a multi-threaded context.
线索是中的被声明in
中将 FilterInputStream
是 protected volatile
。这意味着子类可能会进入并在 null
分配给。鉴于这种可能性,别名实际上是为了防止竞争条件。
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.
考虑没有别名的代码
private InputStream getInIfOpen() throws IOException {
if (in == null)
throw new IOException("Stream closed");
return in;
}
- 线程A调用
getInIfOpen()
- 线程A在== null 中计算
并看到
in
不是null
。 - 线程B指定
null $ c
中的$ c>到。
- 线程A在中执行
返回。返回
null
因为a
是volatile
。
- Thread A calls
getInIfOpen()
- Thread A evaluates
in == null
and sees thatin
is notnull
. - Thread B assigns
null
toin
. - Thread A executes
return in
. Which returnsnull
becausea
is avolatile
.
别名阻止了这一点。现在中的只被线程A读取一次。如果线程B在线程A null
>在中没关系。线程A将抛出异常或返回(保证)非空值。
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.
这篇关于为什么BufferedInputStream将字段复制到局部变量而不是直接使用该字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!