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 >