non*_*tor 20 java constructor initialization thread-safety
我听说过由于构造不正确的对象而在非线程安全的代码中发生这种情况,但即使在Goetz的书中阅读之后我也没有理解这个概念.我想巩固我对这种代码气味的理解,因为我可能会这样做,甚至没有意识到.请在解释中提供代码以使其粘贴,谢谢.
KLE*_*KLE 24
示例:在构造函数中,您创建一个事件侦听器内部类(它具有对当前对象的隐式引用),并将其注册到侦听器列表.
=>所以你的对象可以被另一个线程使用,即使它没有完成执行它的构造函数.
public class A {
private boolean isIt;
private String yesItIs;
public A() {
EventListener el = new EventListener() { ....};
StaticListeners.register(el);
isIt = true;
yesItIs = "yesItIs";
}
}
Run Code Online (Sandbox Code Playgroud)
稍后可能发生的另一个问题:对象A可以完全创建,可供所有线程使用,由另一个线程使用...除了该线程可以看到A实例为创建,yesItIs带有"yesItIs"值,但是不isIt!信不信由你,这可能发生!会发生什么:
=> 同步只是阻塞线程的一半,另一半是关于线程间可见性.
Java选择的原因是性能:如果所有数据都与所有线程共享,则线程间可见性会破坏性能,因此只保证同步数据被共享...
Jon*_*eet 17
非常简单的例子:
public class Test
{
private static Test lastCreatedInstance;
public Test()
{
lastCreatedInstance = this;
}
}
Run Code Online (Sandbox Code Playgroud)
这就是为什么双重检查锁定不起作用的原因.天真的代码
if(obj == null)
{
synchronized(something)
{
if (obj == null) obj = BuildObject(...);
}
}
// do something with obj
Run Code Online (Sandbox Code Playgroud)
不安全,因为对局部变量的赋值可以在构造的其余部分(构造函数或工厂方法)之前发生.因此,线程1可以在BuildObject步骤中,当线程2进入同一块时,检测到非空obj,然后继续操作不完整的对象(线程1已经在呼叫中调度出来).
public class MyClass{
String name;
public MyClass(String s)
{
if(s==null)
{
throw new IllegalArgumentException();
}
OtherClass.method(this);
name= s;
}
public getName(){ return name; }
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,OtherClass.method()传递的实例MyClass是在那个点上未完全构造的,即尚未履行name属性为非null 的契约.