下面的例子来自Brian Goetz的书"Java Concurrency in Practice",第3章,第3.5.1节.这是不正确发布对象的示例
class someClass {
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
}
public class Holder {
private int n;
public Holder(int n) { this.n = n; }
public void assertSanity() {
if (n!=n)
throw new AssertionError("This statement is false");
}
}
Run Code Online (Sandbox Code Playgroud)
它表示Holder可能出现在另一个处于不一致状态的线程中,而另一个线程可能会观察到部分构造的对象.怎么会发生这种情况?你能用上面的例子给出一个场景吗?
此外,它继续说有一种情况,当一个线程第一次读取一个字段时可能会看到一个陈旧的值,然后下次再看到一个更新的值,这就是assertSanity可以抛出断言错误的原因.如何抛出assertionError?
从进一步阅读,解决这个问题的一种方法是通过使变量'n'最终使Holder不可变.现在,让我们假设持有人不是无法忍受的,而是有效的不可改变的.为了安全地发布这个对象,我们是否必须使holder初始化为静态并将其声明为volatile(静态初始化和volatile或者只是volatile)?就像是
public class someClass {
public static volatile Holder holder = new Holder(42);
}
Run Code Online (Sandbox Code Playgroud)
感谢您的帮助.
给定具有变量x的A类.变量x在类构造函数中设置:
A() {
x = 77;
}
Run Code Online (Sandbox Code Playgroud)
我们想将x发布到其他一些线程.考虑以下3个变量x线程安全(?)发布的情况:
1)x是最终的
2)x是易变的
3)x在同步块中设置
synchronized(someLock) {
A a = new A();
a.x = 77;
}
Run Code Online (Sandbox Code Playgroud)
Thread2只打印x:
System.out.println(a.x);
Run Code Online (Sandbox Code Playgroud)
问题是:是否可以观察到Thread2打印的'0'?或者JMM保证将打印'77'或者在所有3种情况下都会抛出NPE?
考虑以下课程:
public class MyClass
{
private MyObject obj;
public MyClass()
{
obj = new MyObject();
}
public void methodCalledByOtherThreads()
{
obj.doStuff();
}
}
Run Code Online (Sandbox Code Playgroud)
由于obj是在一个线程上创建并从另一个线程访问的,因此当调用methodCalledByOtherThread时,obj可能为null吗?如果是这样,将obj声明为volatile是解决此问题的最佳方法吗?声明obj作为最终会有什么不同吗?
编辑:为清楚起见,我认为我的主要问题是:其他线程是否可以看到obj已经被某个主线程初始化或者obj可能是陈旧的(null)?
(我希望我可以为实现线程的所有类构造语言标记这个问题,但是这里有Java,C++,C#和Ruby.不是我对所有这些都很酷)
我想我已经在博客文章/教程上看到过这种效果的陈述(类构造函数是线程安全的).我无法追踪任何直接的陈述,但许多帖子和教程都做出了假设,或者甚至没有提到在构造函数和析构函数上运行的线程问题.坚持Java,它有一个历史和一些正式的多线程方法,
所有这些文章/网页都以自信的方式编写,并包含全面的讨论.他们都提到了方法同步的Java特性,所以你希望他们可能会提到这会如何影响构造和破坏的特殊方法.但他们没有.
但类构造函数和析构函数需要像任何类方法一样考虑.这是一篇关于Java的文章,
关于从构造函数泄漏'this'引用.这里有几个StackOverflow帖子,
显示具有线程问题的构造函数.我怀疑特殊方法中的线程问题仅限于Java.
所以,我想知道,
是否基于构造函数的总体布局假设了线程安全(无论如何定义)?一个代码不多的紧密编码的构造函数将接近可重入代码(通过参数接受数据等)
或者口译员/编制者是否处理具有特殊待遇或保护的施工人员/破坏者?例如,Java内存模型在构造结束时对期望做出一些评论,我希望其他语言规范也是如此.
维基百科关于构造函数的内容很少.在不同的上下文中,这篇文章中的构造语言中的构造函数包含一些提示,但不是关于线程安全性.
虽然在专业书籍中有许多信息,但是对StackOverflow进行一般性(尽管语言特定的提及很有趣!)解释/讨论会很好.