当我从java阅读源代码时。伊奥。缓冲数据流。getInIfOpen()
,我不明白它为什么会这样写代码:
/**
* 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;
}
为什么它使用别名,而不是直接在中使用字段变量,如下所示:
/**
* 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;
}
有人能给个合理的解释吗?
这是因为类BufferedInputStream
是为多线程使用而设计的。
在这里,您可以看到中的声明,它位于父类
FilterInputStream
中:
protected volatile InputStream in;
由于它是受
中的保护的
,它的值可以被FilterInputStream
的任何子类更改,包括BufferedInputStream
及其子类。此外,它被声明为易失性
,这意味着如果任何线程更改了变量的值,则此更改将立即反映在所有其他线程中。这种组合是不好的,因为它意味着类BufferedInputStream
无法控制或知道何时被更改。因此,该值甚至可以在检查null和返回语句之间更改
中的BufferedInputStream::getInIfOpen
,这实际上使检查null变得无用。通过只读取值一次,将其缓存在局部变量
输入
中,方法BufferedInputStream::getInIfOpen
可以安全地抵抗来自其他线程的更改,因为局部变量总是由单线程。
BufferedInputStream::close
中有一个例子,它将中的
设置为空:
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()
}
}
如果在执行
BufferedInputStream::getInIfOpen
时,另一个线程调用了BufferedInputStream::close
,这将导致上述竞争条件。
如果你断章取义地看这段代码,对这个“别名”没有很好的解释。它只是冗余代码或糟糕的代码风格。
但是上下文是,BufferedInputStream
是一个可以子类化的类,它需要在多线程上下文中工作。
线索是in
中声明的FilterInputStream
是protected
。这意味着子类有可能进入并分配null
到in
。考虑到这种可能性,“别名”实际上是为了防止种族状况。
考虑没有“别名”的代码
private InputStream getInIfOpen() throws IOException {
if (in == null)
throw new IOException("Stream closed");
return in;
}
getInIfOpen()
in==null
并看到in
不是null
。 null
赋值到中的。
- 线程A执行
返回
。它返回null
,因为a
是不稳定的
。
“别名”防止了这种情况。现在
中的只被线程A读取一次。如果线程B在线程A在
中有之后分配
null
,这无关紧要。线程A将抛出异常或返回(保证)非空值。
问题内容: 当我从中读取源代码时,我很困惑为什么它编写了这样的代码: 为什么使用别名而不是直接使用field变量,如下所示: 有人可以给出合理的解释吗? 问题答案: 如果您是从上下文中看这段代码,那么对于“别名”将没有很好的解释。它仅仅是冗余代码或不良的代码样式。 但是上下文是可以被子类化的类,它需要在多线程上下文中工作。 线索是,在宣布IS 。这意味着子类有可能进入并分配给。考虑到这种可能性,实
问题内容: 我正在阅读的源代码,并发现了一些我不理解的代码: 注意这一行: 为什么不直接使用它,而是将其分配给局部变量? 问题答案: 可能是出于 优化 目的吗? 可能可以通过JIT编译器更轻松地将局部变量直接分配给寄存器。 至少在Android中,对于API的第一个版本,访问局部变量比访问实例变量便宜(不能代表较新的版本)。普通的Java可能是相同的,在某些情况下使用本地是有意义的。 实际上,在这
如果我在我的类中创建一个bool,就像一样,它默认为false。 当我在我的方法中创建相同的bool时,我得到一个错误“使用未分配的局部变量检查”。为什么?
:我知道如何: 运行不带参数的私有void方法 :我知道如何: 设置任意类型的私有字段 设置任意类型的私有静态字段 设置任意类型的私有最终字段 设置任意类型的私有静态最终字段 :我知道如何: 获取任何类型的私有字段 :我知道如何: (可用于以单模式创建私有构造函数的新实例,同时保持实例Field为空) 创建不带参数的私有构造函数的新实例 我不知道的,我想知道的: 获取任何类型的私有静态字段,并将其
本地风险值背后的想法是最终的,而领域不是。
我看到了这种奇怪的行为,我想知道是否有合理的解释: 当我(意外地)在函数的局部变量中添加了一个额外的分号时,如: 它确实可以编译,但它表明它是多余的。 但当我对字段执行此操作时(也是偶然),我得到了一个错误(编译): 问题 是否有任何理由限制这些领域? Nb我已经知道了不允许带有字段的另一个限制因素。但这里有所不同。