在Brian Goetz的Java Concurrency in Practice中,有以下示例(列出4.11缩短版)。
public class SafePoint {
private int x, y;
public SafePoint(int x, int y) {
this.x = x;
this.y = y;
}
public synchronized int[] get() {
return new int[] { x, y };
}
public synchronized void set(int x, int y) {
this.x = x;
this.y = y;
}
}
它真的是线程安全的吗? x
和y
既不是volatile
也不是final
,并且它们的设置没有锁定this
,这意味着另一个调用get()
的线程可能会看到陈旧值(零)。我在这里想念一下吗?
答案 0 :(得分:2)
该方法是synchronized
指示的线程保存。至于您的示例中的属性x
和y
,这些属性只能在构造函数中编写。因此,您无需进行synchronized
。如果您为x
和/或y
实施某种设置器,则需要设置这些设置器synchronized
和属性volatile
。
答案 1 :(得分:1)
@jameslarge你读过这个标题吗?...
好的,我在你正在阅读的书的索引中查找了“安全出版物”,这就是它在第3.5.3节中所说的内容:
正确构建的对象可以安全地发布;从
static
初始化程序初始化对象引用,将对它的引用存储到volatile
字段或AtomicReference
中,将对它的引用存储到正确的final
字段中构造对象,或将对它的引用存储到一个被锁定正确保护的字段中。
因此,答案取决于SafePoint
类的使用方式。
如果线程A构造一个SafePoint(5, 15)
实例,然后将其存储在非final
,非volatile
,非 - static
字段,然后是线程B调用safePoint.get()
;返回给主题B的值可以是[0, 0]
,也可以是[5, 0]
,[0, 15]
或[5, 15]
。
如果safePoint
字段为final
或volatile
,或者它是由静态初始化程序设置的static
字段,则返回给主题B的值永远是[5, 15]
。
此示例在我的环境中打印result = [5, 15]
,但如果我读到Goetz先生的书是正确的,那么JLS 允许它返回任何其他三种可能性。
public class SafePointDemo {
SafePoint safePoint;
void threadAwork() {
safePoint = new SafePoint(5, 15);
sleep(15000);
}
void threadBwork() {
sleep(10000);
int[] result = safePoint.get();
System.out.println("result = [" + result[0] + ", " + result[1] + "]");
}
private void sleep(long n) {
try {
Thread.sleep(n);
} catch(InterruptedException ex) {
//do nothing
}
}
class SafePoint {
private int x, y;
public SafePoint(int x, int y) {
this.x = x;
this.y = y;
}
public synchronized int[] get() {
return new int[] { x, y };
}
public synchronized void set(int x, int y) {
this.x = x;
this.y = y;
}
}
public static void main(String[] args) {
SafePointDemo safePointDemo = new SafePointDemo();
Thread threadA = new Thread(() -> safePointDemo.threadAwork());
Thread threadB = new Thread(() -> safePointDemo.threadBwork());
threadA.start();
threadB.start();
}
}
答案 2 :(得分:0)
虽然整数不是最终的,但只是在构造函数中赋予它们值,你实际上是将它们作为最终值,因为在设置整数之前,调用者无法使用指向该对象的指针。
get方法的同步只保证一次只能有一个线程执行get方法,任何其他线程将被挂起,直到第一个完成。