有时由于几个原因,我需要通过setter而不是构造函数来使用注入。所以在这些情况下,我不能将字段标记为final,因为字段值需要在构造后更改。如JMM中所述,如果字段不是final,那么另一个线程可以看到该字段没有完全初始化的值。 guice有没有解决这个问题的方法?
换句话说,guice是否提供保证, A 的方法 foo 总是会看到安全的已发布的实例?
public class A {
// there is no problem with safe publication due to dataSource is final
private final DataSource dataSource;
// potential problem with safe publication due to something is not final
private SomeMutableClass something;
@Inject
public A(DataSource dataSource) {
dataSource = dataSource;
}
@Inject
public void setSomething(SomeMutableClass something) {
this.something = something;
}
public void foo() {
// does another thread can observe incompletly initialized value of something?
something.doSomething();
}
}
答案 0 :(得分:2)
如果我正确理解了这个问题,那就是你在线程1上获得A
的实例,并在线程2上调用a.foo()
的情况。在这种情况下,Guice等同于手动编写
Thread 1 Thread 2
-------------------------------------
A a = new A(dataSource); | // Thread 2 could observe a.something == null
a.setSomething(something); | a.foo();
但是,只有在没有任何形式的同步的情况下将a
从线程1传递到线程2时,才会发生这种情况。 synchronized
块,线程安全的数据结构等具有内存排序保证。