2013-04-09 3 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 практически доступен только для чтения.Доступ к почти-readonly-shared-list Асинхронно

Есть много много потоков, которые имеют экземпляр Foo, им всем нужен указатель на объект PlanetInfo. Как вы можете видеть, internal_getPlanetInfo синхронизирован.

Интересно, могу ли я изменить код, поэтому он может сделать пытается найти нужный PlanetInfo. первая попытка была бы Асинхронно, и (если не будет найдена) второй синхронно. , так что ... mothod getPlanetInfo будет меняться так же, как и в методе internal_getPlanetInfo. Таким образом, в большинстве случаев потоки не будут блокировать друг друга.

вещь, которую я имею в виду, это то, что нить может иметь «устаревшую» -копию 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 обращаются к информации, новый объект будет возвращен.

Смежные вопросы