Ahoj,

k situaci "PROBLEM" od verze 1.5 dojit nemuze. Drive to mozne bylo, ale od 1.5
ma Java "vylepseny" pametovy model a ten zarucuje, ze v okamziku, kdy new vrati
referenci, je objekt inicializovany (tj. probehl jeho konstruktor).

Je vsak mozne neco jineho (mapa je sdilena promenna typu Map):

class Trida {
  int x;
  Trida(int x) {
    this.x = x;
  }
}

Vlakno 1:
Trida p = new Trida(42);
mapa.put("odpoved", p);

Vlakno 2:
Trida p = mapa.get("odpoved");

Pokud Vlakno 2 dostane referenci na objekt vytvoreny vlaknem 1, muze se stat, ze
 v promenne x uvidi hodnotu 0 (defaultni hodnotu). Je to tim, ze program neni
spravne synchronizovan (mezi zapisem do x a ctenim x neni definovan
synchronizacni bod). Vlakno 1 totiz muze mit hodnotu 42 v cache a nemusi ji
okamzite zapsat do sdilene pameti (cache nemusi byt skutecna cache, ale treba
jen registr).

Je-li toto problem, lze to resit zavedenim synchronizacnich bodu nebo
jednoduseji pouzitim modifikatoru final ci volatile. Pokud by promenna x byla
final, bude jeji hodnota vzdy viditelna v ostatnich vlaknech.

Jinak misto Collections.synchronizedMap(...) je lepsi ConcurrentHashMap, ktera
povoluje soubezne cteni.

Z.T.
-- 
Zdenek Tronicek
Department of Computer Science and Engineering
Prague                   tel: +420 2 2435 7410
http://cs.felk.cvut.cz/~tronicek


Cituji z emailu od Jiri Dolezel <[EMAIL PROTECTED]>:

> Ahoj,
> pracuji s JEE aplikaci provozovanou na viceprocesorovem stroji (Java 5), kde
> se casto pouzivaji konstrukce tohoto typu:
>
> **** zacatek prikladu ****
>
> class ProductsCache {
>     // staticka cache: "nazev produktu" -> "DTO produktu"
>     private static final Map<String,Product> cacheOfProducts
>             = Collections.synchronizedMap(new HashMap<String,Product>());
>
>     public Product get(String name) {
>         // nejdrive jej zkusime najit v cache
>         Product product = cacheOfProducts.get(name);
>
>         if (product == null) {
>             // pokud v cache neni, vytvor jej v synchronizovanem bloku
>             synchronized (cacheOfProducts) {
>                 // "double-checked-locking"?
>                 product = cacheOfProducts.get(name);
>
>                 if (product == null) {
>                     // PROBLEM: Muze se nam stat, ze se neuplne
> inicializovany produkt ulozi do cache
>                     // a jine vlakno tak ziska nekonzistentni produkt?
>                     product = new Product(name);
>                     cacheOfProducts.put(name, product);
>                 }
>
>             }
>         }
>
>         return product;
>     }
> }
>
> **** konec prikladu ****
>
> Mam k tomuto kodu dve otazky:
> 1) Muze skutecne dojit k situaci popsane v kodu jako "PROBLEM"? Podle me ano,
> pokud prekladac/CPU prohodi instrukce takto:
> - (vlakno A) vytvor novy objekt Produkt "nazev"
> - (vlakno A) proved cacheOfProducts.put("nazev", product);
> - (vlakno B) zavolej cacheOfProducts.get("nazev") => ziska nekonzistentni
> produkt
> - (vlakno A) dokonci inicializaci produktu "nazev"
>
> 2) Pokud skutecne muze nastat situace 1), nabizi Java 5 moznost, jak tomu
> predejit, aniz bychom synchronizovali celou metodu get()?
>
> Zkoumal jsem pouziti volatile za timto ucelem (tzn. deklarovat
> cacheOfProducts jako volatile), ale to se vylucuje s final.
> Ikdyby vsak cacheOfProducts nebylo final, resilo by volatile tento problem?
> Ve specifikaci se uvadi, ze prvky pole, ktere je deklarovane jako volatile,
> samy volatile nejsou. A jelikoz kolekce je postavena na polich, tak si
> myslim, ze to problem opet neresi. Ale to jsou jen me dohady.
>
> Prosim, pokud do toho vidite, vysvetlete mi cely problem jednou provzdy :-)
>
> Jirka
>


Odpovedet emailem