我们有一个应用程序,它有一个类,用于保存通过数据库填充的成员。以下是这种情况的代表性例子。
private AtomicBoolean data1Initialized = new AtomicBoolean(false);
protected SomeSynchronizedDataStructure<Object> data1 = <initializeit>;
protected final synchronized void initData1() {
if (data1Initialized.compareAndSet(false, true)){
// Populate data1 data structure from database
}
}
public SomeSynchronizedDataStructure<Object> getData1(){
initData1();
return data1;
}
我们对data1,data2,data3 ... dataN有相同的模式。每个dataStructure都与另一个没有关系,它们只是在同一个类中。跨多个线程访问此数据。关于这种模式的一些问题:
同步这些方法会使线程必须等待所有不同dataN
的布尔检查,对吗?哪个是不必要的?
数据结构是否需要同步?数据在整个应用程序生命周期内不会发生变化。我认为只有初始化它才需要同步,访问可能会发生不同步。
对我个人最重要
这会导致死锁吗?我想不,但我对线程没有经验。
答案 0 :(得分:3)
当您在课堂创作时初始化时,您只需要:
public class DataHolder {
// Note: 'final' is needed to ensure value is committed to memory before DataHolder
private final SomeSynchronizedDataStructure<Object> data1 = <initializeit>;
public SomeSynchronizedDataStructure<Object> getData1(){
return data1;
}
}
因为“initializeit”代码将在类的构造函数中运行,所以当你有一个可以传递的类句柄时,它就会准备就绪。 E.g:
DataHolder dataHolder = new DataHolder();
// dataHolder has already created the data structure by the time I do...
dataHolder.getData1();
如果您确实想要使用延迟加载,只需使用synchronized:
public class DataHolder {
private SomeSynchronizedDataStructure<Object> data1;
public synchronized SomeSynchronizedDataStructure<Object> getData1() {
// synchronized guarantees each thread will see "data1" just as the
// last thread left it.
if(data1 == null) {
data1 = initializeit();
}
return data1;
}
}
答案 1 :(得分:1)
同步这些方法会使线程必须等待所有不同数据N的布尔检查,对吗?
正确。
哪个不必要?
是的,这是不必要的,因为数据N是不相关的。
数据结构是否需要同步?数据在整个应用程序生命周期内不会发生变化。我认为只有初始化它才需要同步,访问可能会发生不同步。
再次,正确。 BarrySW19的答案为您提供了安全初始化而无需同步的模式。
对我个人最重要
这会导致死锁吗?我想不,但我没有线程经验。
它本身不会导致死锁。但是,如果其中一个数据init方法调用在另一个监视器上同步的其他东西(称之为m),同时其他一些线程拥有m并且现在尝试初始化其中一个dataNs,那就是死锁。