Cituji z emailu od Lukas Barton <[EMAIL PROTECTED]>: > Zdeněk Troníček wrote: > > 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). > > > Todle prave v 1.5 neplati! Instrukce se porad muzou libovolne prehazet :-) > Instrukce se nemuzou prehazovat pres zapis do volatile nebo prechod pres > synchronizovanou sekci (tj. ostatni vlakna vidi, ze vsechno je provedeno > pred vstupem do synchronizovane sekce / zapisem do volatile).
Ano, muze dochazet k prehozeni instrukci (muze to provest compilator, JIT, nebo to muze byt dusledek cache). Toto je ovsem vyjimka. Viz specifikace na str. 322: "Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure: ..." > V 1.4 a driv vyse uvedene neplatilo prave pro volatile. A neslo tedy > double-check-locking opravit nastavenim te promene na volatile. V 1.4 nebylo dovoleno prohazovat pristupy k volatile promennym. Bylo ovsem mozne prohazovat tyto pristupy s pristupy k non-volatile promennym. Od verze 1.5 neni mozne ani toto. To co je tedy zapsano pred ctenim nebo zapisem volatile promenne, musi pred nim take probehnout. Navic pristup k volatile promenne je synchronizacni bariera, ktera zpusobi, ze data z cache se zapisou do hlavni pameti a tim mohou byt videt z dalsich vlaken (pokud jde o zapis) nebo zneplatni v cache (pokud jde o cteni). Priklad z http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html: class VolatileExample { int x = 0; volatile boolean v = false; public void writer() { x = 42; v = true; } public void reader() { if (v == true) { //uses x - guaranteed to see 42. } } } Jedno vlakno zavola writer() a druhe vlakno zavola reader(). Pokud vlakno v metode reader() vidi v promenne v hodnotu true, v x bude 42. Je to tim, ze pri zapisu do v v metode writer() dojde k zapisu hodnoty 42 do sdilene pameti (jinak by tato hodnota mohla zustat v cache a nebyla by tudiz pro ostatni vlakna viditelna). > > 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. > > > Toto plati (pouze) pro final promene inicializovane v konstruktoru. A na > ty hodnoty musi to druhe vlakno pristupovat pres tu final promenou. > Pricemz tato vlastnost je tranzitivni. Plati to i pro promenne inicializovane inicializatorem. Tj. public class X { final double RATE = Math.random(); ... } Pokud jde o pristup k finalni promenne, tak nevidim duvod, proc by nemel fungovat getter. public class X { private final double RATE = Math.random(); public double getRate() { return RATE; } } Z.T. -- Zdenek Tronicek Department of Computer Science and Engineering Prague tel: +420 2 2435 7410 http://cs.felk.cvut.cz/~tronicek
