我有以下对象:
// this class is immutable, acts like container for several properties.
public class MyDataAddOps{
private final boolean isActive;
private final Map<String,Object> additionalProps;
public MyDataAddOps(boolean isActive, Map<String,Object> additionalProps){
this.isActive = isActive;
this.additionalProps = additionalProps;
}
public boolean isActive(){return isActive;}
public Map<String,Object> getAdditionalProps(){ return additionalProps;}
}
// this class acts as "spring" bean that calls load on construction,
// and then another scheduler bean calls the load per some cron expression (once a minute for example)
public class MyDataAddOpsService{
private MyDataAddOps data;
// this method will be executed periodically outside
// via some spring quartz for example
// the quartz is not re-entrant
public void load(){
// opens some defined file and returns content string
String fileData = getFileContent();
boolean isActive = getIsActive(fileData);
Map<String, Object> props = getProps(fileData);
data = new MyDataAddOps(isActive, props);
}
// This method is executed by many workers threads inside the application
public boolean isActive(){
return data.isActive();
}
public final Map<String, Object> getProps(){
return data.getAdditionalProps();
}
}
这种方法可能存在竞争条件,其中一个线程执行isActive()
而另一个load()
。虽然它在引用上运行但对象状态没有改变。
支持此类并发的最佳解决方案是什么?我想避免同步方法,还有读写锁。
可能是AtomicReference
还是volatile
?或者,如果没有代理方法,只返回对数据本身的引用会更好?所以根本不需要锁定,并且所有使用逻辑都在此服务之外?
public class MyDataAddOpsService{
private MyDataAddOps data;
public void load(){
....
data = new MyDataAddOps(isActive, props);
}
public MyDataAddOps getData(){
return data;
}
}
答案 0 :(得分:5)
Your code has yet to grow towards having a race condition; currently it contains something much more severe, which is a data race. Publishing a reference across threads without inducing a happens before relationship between the write and the future reads means that the reader can see the data object in a partially initialized, inconsistent state. Your proposal of a solution does not help with that.
Once you make the data
field volatile
, only then will you have a race condition between one thread first reading the data
reference, then another thread updating the data
reference, then the first thread reading isActive
from the old data. This may actually be a benign case for your logic.