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同期されています。

コードを変更できるかどうか疑問に思うので目的のPlanetInfo. 最初の試行はAsynchronouslyになり、(見つからない場合は) 2 回目は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

あなたが説明していることは、特に高レベルの同時実行のコンテキストでは、実際には優れたアイデアです。以下のパターンは、「値」が 1 回だけ計算され、クリティカル セクションが最小回数実行されることを保証します。言語中立の擬似コードでは、パターンは次のようになります。

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 に答える