繁体   English   中英

这不是用Java解释Final的不好例子吗?

[英]Isn't this a bad example for explaining Final in Java?

Java规范17.5具有以下代码,以说明Java内存模型中最终字段的使用。 (与普通字段相比)

class FinalFieldExample { 
    final int x;
    int y; 
    static FinalFieldExample f;

    public FinalFieldExample() {
        x = 3; 
        y = 4; 
    } 

    static void writer() {
        f = new FinalFieldExample();
    } 

    static void reader() {
        if (f != null) {
            int i = f.x;  // guaranteed to see 3  
            int j = f.y;  // could see 0
        } 
    } 
}

规范继续说:

“ FinalFieldExample类具有一个最终的int字段x和一个非最终的int字段y。一个线程可能执行方法writer,而另一个线程可能执行方法reader。由于writer方法在对象的构造函数完成后写入f,因此reader方法将确保可以看到fx的正确初始化值:它将读取值3。但是,fy不是最终值;因此,不能保证reader方法会看到其值4。”

我的问题是:这不是一个me脚(或至少一个人为设计不佳的例子)吗? 还是我在这里想念什么?

我将此示例称为“ lam叶”的理由是:

如果要在多线程方案中由线程共享FinalFieldExample类的对象,则不应遵循多线程的基本原则,即使用某种形式的同步。 如果他们使用同步,则提到的问题将不存在。

上面的示例似乎主张将Final字段用作适当同步技术的替代(或部分安抚奶嘴)。 以我的理解,即使在正确同步的基础上使用final字段也是如此。 并且决不能用来获得示例中提到的优势(在没有同步的情况下)。

所以有人会问:难道没有一个像样的例子(带有同步)来解释最终字段比普通字段的优势吗? 我想,不变性是!

您在混淆synchronization和并发性。

如果字段是常量,则可以在多个Thread之间安全地共享它,而无需锁定。

如果字段是变量,则需要synchronized或锁定它。

您可以有一个并发程序,其中有多个线程读取相同的常量字段,这不会阻塞任何Thread

任何使用synchronized块的代码都会付出巨大的代价。 这是一个非常昂贵的过程,应尽可能避免。 更不用说资源匮乏,死锁,活动锁等问题了...

如果可以使用final而不是synchronized ,则应该这样做。

编辑:我错过了这个答案的重点。 问题不是值可以更改。 请参阅bmorris591的答案。

不变对象的优点之一是您不需要同步。

但是此示例与同步无关,而是与确保阅读器线程看到的值有关。 即使进行同步, y的值也可能会更改,而x的值始终保证为3。

您引用的该规范仅描述了(应该)行为。 根据此规范,您可以决定如何正确编码。 此示例绝不尝试表示真实的用例。 它仅用几行说明了行为是什么。 而且,如果您的jvm实现不像那样,那就是一个错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM