2013-04-09 108 views
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。第一個 嘗試將是異步,和(如果找不到然後做)第二個同步。 so ...方法getPlanetInfo將執行與方法internal_getPlanetInfo不同的for-loop。因此,大多數時候線程不會互相鎖定。

我記住的事情是,一個線程可能有一個「陳舊」 - Infos.planets,但是!這個「過時」拷貝的唯一潛在問題是它錯過了一段時間後添加的項目。所以如果找不到所需的項目,我們使用「master」 -copy來查找它。

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); 
} 

任何意見將不勝感激!

ido。

回答

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對象訪問信息時,新對象將被返回。