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


Odpovedet emailem