0
public class PlanetInfo {
    String planetName="";
    int a;
    int b;
    int c;

    PlanetInfo(planetname){
        planetName = planetname;
        if(planetName.equals("earth")){
            a=1;
            //....
        }
        else if(planetName.equals("mars")){
            a=2;
            //....
        }
    }       
}

public final class Infos {
    static final LinkedList<PlanetInfo> planets = new LinkedList<PlanetInfo>();

    private static synchronized PlanetInfo internal_getPlanetInfo(String planetName){
        for(int i=0;i<planets.size();i++){
            if(planets.get(i).planetName.equals(planetName)){
                //return existing PlanetInfo:
                return planets.get(i);
            }
        }

        //if not found then create and return a new one:
        return new PlanetInfo(planetName);

    }

    public static PlanetInfo getPlanetInfo(String planetName){
        return internal_getPlanetInfo(planetName);
    }
}


public class Foo {    
    PlanetInfo planetinfo = null;
    public Foo(aplanet){
        planetInfo = Infos.getPlanetInfo(aplanet);
    }

    public void dosomthing(){
        if(planetInfo.a==1){//please, do not wonder about thread-safe here, it's just a simplification...
            // etc....
        }
    }


}

创造新需求的情况很少见PlanetInfo,但它确实发生了。一旦PlanetInfo创建并添加到Infos.planets它永远不会被删除。大多数时候,Infos.planets实际上是只读的。

有很多线程都有 的实例Foo,它们都需要一个指向PlanetInfo对象的指针。如您所见,internal_getPlanetInfo是同步的。

我想知道我是否可以更改代码,所以它可能会尝试2 次来找到所需的PlanetInfo. 第一次尝试将是Asynchronously,并且(如果没有找到那么做)第二次synchronously。所以......该方法getPlanetInfo将执行与方法相同的for循环internal_getPlanetInfo。因此,大多数时候线程不会相互锁定。

我想到的是一个线程可能有一个“陈旧”的副本Infos.planets但是!这个“陈旧”副本的唯一潜在问题是它错过了一段时间后添加的项目。因此,如果找不到所需的项目,那么我们使用“主”副本查找它。

public static PlanetInfo getPlanetInfo(String planetName){
    //try to find it Asynchronously:
    for(int i=0;i<planets.size();i++){
        if(planets.get(i).planetName.equals(planetName)){
            return planets.get(i);
        }
    }
    //if not found then do it synchronously:
    return internal_getPlanetInfo(planetName);
}

任何意见将不胜感激!

我做。

4

1 回答 1

0

您所描述的实际上是一个绝妙的想法,尤其是在高度并发的情况下。下面的模式将确保“值”只计算一次,并且关键部分被执行最少次数。在与语言无关的伪代码中,模式如下:

if value is-not-available then
    // Entering critical section
    if value is-not-available then
        value = comupte-the-value
    // Exit critical section.
}
return value;

我建议,如果还不是这样的话,PlanetInfo 对象是不可变的,并且当它们的信息发生更改时,您只需要创建一个具有更改值的新对象。只读对象避免了很多并发问题。

过时问题可以通过额外的间接级别轻松解决。相反,Foo 持有一个 PlanetInfo 参考,他们应该保持一个 planetInfoIndex(进入 Info.planets)。当已知有关行星的新信息时,该索引处的引用将替换为新的不可变对象。下次任何 Foo 对象访问该信息时,将返回新对象。

于 2013-04-21T17:03:42.640 回答