假设我们有非常简单的
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; } }
>使字段数变动.
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节中描述的这种方法的经典版本.有趣的是,它在本书的勘误表中提到的示例中有错误.
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指定的逻辑序列和发生之前的关系.它可能会导致未正确构造到另一个线程的发布对象.
关于第三种情况,我有几个问题.
>它将等同于以下代码:
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可能会重新排序内容,因此在字段中使用默认值发布对象?
>如果第二个问题的答案是肯定的,我还有一个问题.
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; } }
这个奇怪的同步(新的Object())应该是防止重新排序的效果.它会工作吗
要清楚,所有这些例子都没有任何实际应用.我只是好奇的多线程的细微差别.
解决方法
synchronized(new Object())将不执行任何操作,因为同步只在同步对象上.因此,如果线程A在一个对象上同步,并且线程B在另一个对象上同步,则它们之间不会发生任何事件.因为我们可以知道一个事实,没有其他线程将永远同步在你创建的新的Object(),这不会建立任何其他线程之间的发生.
关于你在构造函数中的同步,如果你的对象安全地发布到另一个线程,你不需要它;如果不是这样,你可能会遇到麻烦.我曾经问过这个和并发兴趣列表的问题,还有an interesting thread resulted.特别看到this email,它指出即使你的构造函数同步,在没有安全发布的情况下,另一个线程可以在你的字段中看到默认值,而this email哪个(imho)将整个事情联系在一起.