首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么BufferedInputStream要将字段复制到局部变量而不是直接使用该字段

为什么BufferedInputStream要将字段复制到局部变量而不是直接使用该字段
EN

Stack Overflow用户
提问于 2016-03-26 10:42:04
回答 3查看 2.5K关注 0票数 106

当我阅读java.io.BufferedInputStream.getInIfOpen()的源代码时,我很困惑为什么它会写成这样的代码:

代码语言:javascript
复制
/**
 * 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;
}

为什么使用别名而不是直接使用字段变量in,如下所示:

代码语言:javascript
复制
/**
 * 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;
}

有人能给出一个合理的解释吗?

EN

回答 3

Stack Overflow用户

发布于 2016-03-26 10:59:26

这是因为BufferedInputStream类是为多线程使用而设计的。

在这里,您可以看到放置在父类FilterInputStream中的in声明

代码语言:javascript
复制
protected volatile InputStream in;

因为它是protected,所以它的值可以由FilterInputStream的任何子类更改,包括BufferedInputStream及其子类。此外,它被声明为volatile,这意味着如果任何线程更改了变量的值,此更改将立即反映在所有其他线程中。这种组合是不好的,因为它意味着类BufferedInputStream无法控制或知道in何时发生更改。因此,甚至可以在检查null和BufferedInputStream::getInIfOpen中的return语句之间更改该值,这实际上使得对null的检查变得无用。通过只读取一次in的值以将其缓存在局部变量input中,方法BufferedInputStream::getInIfOpen不会受到其他线程的更改,因为局部变量始终归单个线程所有。

BufferedInputStream::close中有一个示例,它将in设置为null:

代码语言:javascript
复制
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,则会导致上述争用情况。

票数 20
EN

Stack Overflow用户

发布于 2016-03-26 10:59:38

这是一段很短的代码,但从理论上讲,在多线程环境中,in可能会在比较后立即更改,因此该方法可能会返回未检查的内容(它可能返回null,从而做它想要阻止的事情)。

票数 6
EN

Stack Overflow用户

发布于 2016-03-26 11:02:03

我相信,将类变量in捕获为局部变量input可以防止在getInIfOpen()运行时另一个线程更改in时出现不一致的行为。

请注意,in的所有者是父类,并且没有将其标记为final

这种模式在类的其他部分中也被复制,似乎是合理的防御性编码。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36231047

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档