[英]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.