假设我有下一个类:class Point { int x, y, z; public Point(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } public **synchroni...
假设我有下一堂课:
class Point {
int x, y, z;
public Point(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public **synchronized** int getSum() {
return x + y + z;
}
}
如果我要共享对多个线程的引用,是否可以在 同步的 getSum() 方法中拥有部分初始化的字段?
Point p = new Point(1,2,3);
int sum = p.getSum();
是否有可能得到如下结果:
sum = 0 (OK);
sum = 6 (OK);
sum = 1 (x = 1, y = 0, z = 0) (INTERESTING);
sum = 2 (x = 0, y = 2, z = 0) (INTERESTING);
sum = 3 (x = 0, y = 0, z = 3) (INTERESTING);
sum = 5 (x = 1, y = 2, z = 3) (INTERESTING);
and so on..
这里确实存在先发生保证吗?如果一个线程获得 Point 的锁并进入同步方法,是否意味着调用构造函数的线程已经完成了所有初始化?
对我来说,显然有可能得到以下结果:
sum = 0 (OK);
sum = 6 (OK);
那么下一个不变量呢?有可能吗?
sum = 1 (x = 1, y = 0, z = 0) (INTERESTING);
sum = 2 (x = 0, y = 2, z = 0) (INTERESTING);
sum = 3 (x = 0, y = 0, z = 3) (INTERESTING);
sum = 5 (x = 1, y = 2, z = 3) (INTERESTING);
我认为 Point 对象的引用在多个线程之间共享,没有适当的同步或安全发布,因此无法保证其他线程将看到完全构造的对象。这意味着如果对象未安全发布,线程可能会观察到部分初始化的字段。同步方法不能保证对象本身的安全发布。如果对象未安全发布,另一个线程可能会观察到部分构造的 Point 对象,即使在调用同步的 getSum() 方法时也是如此。
因此,没有先发生保证...你同意我的观点吗?
有一个有趣的答案 在构造函数中进行同步以使其先发生 。但我不同意:
任何同步方法(或块)都保证能看到构造函数的全部效果,或者看不到任何效果;它不会只看到构造函数的一部分
我说得对吗?