考虑一下我有这段Java代码
我想知道是否有一种无锁机制可以使突出显示的代码片段成为原子。我想避免当有人拨打fetchSomeThing()
时,我正处于BlockX
的中间,fetchSomeThing()
正在查看A的新副本,但是B和C的旧副本。
public class MyClass
{
private volatile Map a, b, c;
public void refresh()
{
Map a_ = loadA();
Map b_ = loadB();
Map c_ = loadC();
//I want to make the following block atomic
// call it Block X
{
this.a = a_;
this.b = b_;
this.c = c_;
}
}
public String fetchSomeThing()
{
// some joint operations on this.a, this.b and this.c
}
}
我能想到的唯一方法是将它分成两个类,并将a,b,c包装在一个对象中。
但这非常麻烦。有没有更好的办法?
public class MyShadowClass
{
private Map a, b, c;
public MyShadowClass()
{
init();
}
public void init()
{
Map a_ = loadA();
Map b_ = loadB();
Map c_ = loadC();
this.a = a_;
this.b = b_;
this.c = c_;
}
public String fetchSomeThing()
{
// some joint operations on this.a, this.b and this.c
}
}
public class MyClass
{
private volatile MyShadowClass shadow;
public void refresh()
{
MyShadowClass tempShadow = new MyShadowClass();
shadow = tempShadow;
}
public String fetchSomeThing()
{
return shadow.fetchSomeThing();
}
}
答案 0 :(得分:1)
只需使复合对象保持当前有效状态即可。然后,您可以使用AtomicReference来管理当前状态:
private AtomicReference<Thing> currentThing = new AtomicReference<Thing>();
public Thing getThing() {
while (true) {
Thing result = currentThing.get();
if (result != null)
return result;
result = buildThing();
if (currentThing.compareAndSet(null, result);
return result;
}
}
private Thing buildThing() {
// whatever, only important thing is that this creates
// a new and valid instance of Thing
}
public void refresh() {
Thing freshThing = buildThing();
currentThing.set(freshThing);
}
如果你可以确保只有一个线程写入该字段,或者你并不特别关心在refresh()和initial时获取相同的实例,那么你可以简单地将“currentThing”声明为正常,但是挥发性字段get正在同时执行。