Java 中的线程安全类,通过同步块
假设我们有非常简单的Java类。MyClass
public class MyClass {
private int number;
public MyClass(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
有三种方法可以构造具有某种状态的线程安全 Java 类:
-
让它真正不可变
public class MyClass { private final int number; public MyClass(int number) { this.number = number; } public int getNumber() { return number; } }
-
使字段 。
number
volatile
public class MyClass { private volatile int number; public MyClass(int number) { this.number = number; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } }
-
使用块。在实践中,Java 并发的第 4.3.5 章中描述的此方法的经典版本。有趣的是,它在本书的勘误表中提到了一个错误。
synchronized
public class MyClass { private int number; public MyClass(int number) { setNumber(number); } public synchronized int getNumber() { return number; } public synchronized void setNumber(int number) { this.number = number; } }
还有一个事实应该添加到讨论的背景下。在多线程环境中,JVM 可以自由地对块外的指令进行重新排序,从而保留 JVM 指定的逻辑序列和发生前关系。它可能会导致尚未正确构造的发布对象到另一个线程。synchronized
关于第三种情况,我有几个问题。
-
它是否等效于以下代码段:
public class MyClass { private int number; public MyClass(int number) { synchronized (this){ this.number = number; } } public synchronized int getNumber() { return number; } public synchronized void setNumber(int number) { this.number = number; } }
在第三种情况下,是否会阻止重新排序,或者JVM可以对指令进行重新排序,从而在字段中发布具有默认值的对象?
number
-
如果第二个问题的答案是肯定的,那么我还有一个问题。
public class MyClass { private int number; public MyClass(int number) { synchronized (new Object()){ this.number = number; } } public synchronized int getNumber() { return number; } public synchronized void setNumber(int number) { this.number = number; } }
这种奇怪的外观应该防止重新排序的效果。它会起作用吗?synchronized (new Object())
需要明确的是,所有这些例子都没有任何实际应用。我只是对多线程的细微差别感到好奇。