2013-04-12 31 views
1

Java规范17.5具有下面的代码来说明使用最终字段在Java存储模型的。 (相比于普通字段)这不是用Java解释Final的一个坏例子吗?

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有一个最终诠释现场x和非最终诠释字段,Y的 一个线程可以执行。由于writer方法在对象的构造器完成后写入f,读者方法将保证看到fx的正确初始化值:它将读取值3. 但是,fy是不是最终的;读者的方法因此不能保证看到它的价值4。“

我的问题是:这不是一个跛脚(或至少是一个非常做作)的例子吗? 还是我失去了一些东西?

我的推理项的实例为“跛”是:

如果FinalFieldExample类的对象要被通过螺纹在一个多线程的情况下共享,不应该它遵循多线程的基本原则,这是使用某种形式的同步。如果他们使用过同步,那么提到的问题将不存在。

上述例子似乎主张最终字段作为适当的同步技术的替代(或部分橡皮奶头)。根据我的理解,即使在正确的同步之上使用最终字段也是有用的。并且不应该被用来获得示例中提到的优势(在没有同步的情况下)。

所以人们可能要问: 是不是有一个体面的例子(同步于)解释过正常的域最终场的优势在哪里?我猜,不可变性是!

+1

它就是当前内存模型下最终字段发生情况的一个例子。这不是主张你写这样的代码。请参阅JCIP以获取有关如何编写并发代码的建议,其中基本原则是“尽可能使用更高级别的构造(在java.util.concurrent中)”。 –

+0

@NathanHughes:您的评论非常有趣。你能否在JCIP中提供一个参考文件(在使用更高层次的结构时)?谢谢 ! – brainOverflow

+0

尝试JCIP的这句话,第5章开始:“在实际情况下,委派是创建线程安全类最有效的策略之一:让现有线程安全类管理所有状态。” –

回答

4

你混淆了synchronization和并发性。

如果一个字段是一个常量,那么它可以安全地在多个Thread之间共享,而不需要任何锁定。

如果一个字段是一个变量,那么它需要是​​或以其他方式锁定。

你可以有一个并发程序有多个线程读取相同的常量字段,这不会阻止任何Thread s。

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

如果您可以使用final而不是​​您应该这样做。

+0

“如果一个字段是一个变量,那么它需要被同步或锁定。”确实!这也是我的观点。由于在这个例子中有一个变量(即非最终),它必须已经同步。这个例子似乎是故意构建的,允许非法访问非最终字段,然后声称这是最终字段的用例。 – brainOverflow

+2

@vendhan不!这是JVM如何运行的一个例子。 JLS不是用例列表,它是对语言规范的描述。这是“final”和“non-final”字段的行为如何不同的例子。 –

+0

这是JLS的一个合理的论点!谢谢 ! – brainOverflow

3

编辑:我错过了这个答案的地步。问题不在于价值可以改变。请参阅bmorris591的回答。

不可变对象的一个​​优点是您不需要同步。

但是这个例子不是关于同步,而是读者线程保证看到的值。即使有同步的y价值可能发生变化,而x值总是保证是3

+0

哇!你能否告诉我们,即使正确的同步,y的价值可能被误读? – brainOverflow

+0

@vendhan正确同步不,它不能。没有它当然可以。关键是,虽然y是一个常数,但仍然可能被误读,因为它不是“最终”。 –

+2

这不是它可能被误读,而只是它可以被另一个线程改变。 – WilQu

1

你引用的这个规范只是描述了东西(应该)的行为。根据此规范,您可以决定如何正确编码。这个例子绝不会试图代表一个真实的用例。它只是用几行说明行为是什么。如果你的jvm实现不像那样,那么它就是一个bug。

相关问题