tifyty

pure Java, what else ?

Tudásteszt, multi thread 1

Van egy osztály

class Test {
           static volatile int i = 0, j = 0;
           static void one() { i++; j++; }
           static void two() {
               System.out.println("i=" + i + " j=" + j);
           }
}

amelynek one nevű metódusát egy szál hívogatja, maximum Integer.MAX_VALUE esetben. Azért ez nem kevés. Egy másik szál pedig a two nevű metódust hívogatja. A kérdés az, hogy a kiíratás során milyen lehetőségek fordulhatnak elő. Több választ is meg lehet jelölni, de csak azért, hogy elbizonytalanítsalak. Lehet, hogy csak egy válasz a jó?

Extra kérdés bónuszpontért: honnan vettem a fenti mintapéldát?

UPDATE 2013. január 4 7:12

Nem gondoltam volna, hogy ilyen hamar megérkezik a teljesen korrekt válasz:


Kofa február 3, 2013 – 11:17 du. (Szerkesztés)

Szerintem mind igaz.
Az olvasó szál futhat az mindkét increment futása után, ekkor egyenlőek.
Futhat i++ után, j++ előtt, ekkor i>j.
Végül előfordulhat, hogy i-t kiolvasta, felfüggesztődik, párszor megfut a növelés, és az ezután kiolvasott j értéke magasabb lesz, mint a korábban kiolvasott j.

A tippem az volt, hogy a JLS-ből vetted, és ezt azóta ellenőriztem is. 🙂

Nem azért nem gondoltam, mert hülyének gondolom az olvasóimat, hanem mert hétvége volt. Őszintén: kellemes meglepetés. Persze Kofa-t ki kellett volna zárnom a megoldók köréből, kollégám, és naná, hogy tudja: ő tartja nálunk a Java multi-thread tréninget.

És akkor még a motivációimról, hogy miért raktam ki ezt a postot: Nekem nagy gyakorlatom van multi-thread-ben (gondoltam én gyarló módon). A puding próbája, hogy megeszik, és azért az általam írt index hirdetési szerver kilenc évig futott éles környezetben, márpedig az egy darab C-ben megírt http szerver hirdetési logikával hard core multi-thread.

Ha megnézzük néhány válasz stílusát látszik, egy-egy rossz válasszal együtt, akkor azt láthatjuk, hogy mások is hasonló cipőben járnak. Nincs ezzel semmi baj, mind a négy állítás igaz, leginkább az utolsó: a többszálú programozás mágia. (És akkor még nem is tudtam, hogy mekkora pofonba szaladok bele a következő poszttal, amire megint csak Kofa hívta fel a figyelmemet.) De vissza tértve: azért raktam ki ezt a posztot, mert azt gondoltam, hogy nekem nagy gyakorlatom van többszálú programok írásában, nemrég Kofa tréningjén át is ismételtem, megismertem, hogy a Java-nak milyen specialitásai vannak ezen a téren. Meg volt a múlt héten a listán a final használatáról egy kis burst, ami egyrészt szintaktikus cukorka, másrészt viszont pont az MT esetében van jelentősége. Miközben megírtam a postot amit szerdán szándékozom kitenni, átnéztem, hogy mit ír a JLS. Ott találtam ezt a kódot, és következő részt benne:

Therefore, the shared value for j is never greater than that for i, because each update to i must be reflected in the shared value for i before the update to j occurs. It is possible, however, that any given invocation of method two might observe a value for j that is much greater than the value observed for i, because method one might be executed many times between the moment when method two fetches the value of i and the moment when method two fetches the value of j.

Nem értettem, és el is felejtettem olvasás közben, hogy egy oldallal előbb ott szerepelt, hogy kettő szál fut csak, és arra gondoltam, hogy ha rengeteg szál hívja a one() metódust, és mind szuszpendálódik az i növelése után, akkor az i lehet sokkal nagyobb, mint a j, vagyis hibás a specifikáció. Ami a legszégyenteljesebb, még meg is írtam az ORACLE-nek. Meglepő módon még aznap egy teljesen korrekt választ kaptam. Tanulságul legyen itt a levéltitok megsértésével a magánlevelezésünk:

Subject: Java7 spec documentation error, minor
From: Peter Verhas
To: javasedocs_us@oracle.com

http://docs.oracle.com/javase/specs/jls/se7/jls7.pdf

page 210

text reads:

“Therefore, the shared value for j is never greater than that for i,
because each update to i must be reflected in the shared value for i
before the update to j occurs. It is possible, however, that any given
invocation of method two might observe a value for j that is much
greater than the value observed for i, ”

I suspect the correct sentence would be:

“Therefore, the shared value for j is never greater than that for i,
because each update to i must be reflected in the shared value for i
before the update to j occurs. It is possible, however, that any given
invocation of method two might observe a value for i that is much
greater than the value observed for j, ”

Seems that the two variables are mixed in the second part of the
sentence. Even though this is a minor mistake it makes understanding harder.


Peter Verhas

és a válasz kevesebb, mint 12 órával későbbről:

Hi Peter,

Good question, but the text is correct. We can agree that method “one” will always observe values of i and j for which i>=j holds. Method “two” observes the value of i (which is definitely >=j at the time of observation) and appends it to a string … then execution switches to method “one” for a week. When method “two” resumes, the values of i and j will have increased considerably. The invariant i>=j still holds, but method “two” observed i last week – its value was appended to a string! Method “two” now observes j, and of course j is considerably larger than either i or j a week earlier.

Alex

1. Jó pap holtig tanul.

2. Faith in humanity (ORACLE) restored.

11 responses to “Tudásteszt, multi thread 1

  1. tamasrev február 3, 2013 2:21 du.

    Szerintem sokkal izgalmasabb, hogy melyik állapot hogyan állhat elő

  2. Tom február 3, 2013 3:19 du.

    volatile-lal első kettő, nélküle lehetne mind3

    multithread prog nem varázslat csak érteni kell(ene) hozzá 😀

  3. alma február 3, 2013 6:36 du.

    It is possible, however, that any given invocation of method two might observe a value for j that is much greater than the value observed for i, because method one might be executed many times between the moment when method two fetches the value of i and the moment when method two fetches the value of j.

  4. Laca február 3, 2013 6:48 du.

    Hat, en az i>=j -re szavaztam, ennek ellenere miutan kiprobaltam i<j-t is tapasztaltam… 😐

    gcc-vel forgattam linux alatt, optimalizacio nelkul.

  5. ern0 február 3, 2013 10:14 du.

    Minden lehet, még akár egyenlő is. Threads are evil. Valószínűleg lelki adottság kell ahhoz, hogy valaki felfogja a multithreadinget, mert álláshirdetésekben láttam, hogy olyan prgmozókat keresnek, akik értenek hozzá. Pedig az álláshirdetések nem szoktak tömve lenni szakmailag fontos dolgokkal, ugye, egy kis buta HR-es picsa (most kicsit visszafogottan fogalmaztam) csak azt a feladatot tudja megugrani, hogy XYZ és ABC library-kat ismeri-e a jelentkező, el tudom képzelni, a vezető prgmozónak mekkora erőfeszítésébe kerülhetett, hogy ezt a thread-es kitételt beleerőszakolja az álláshirdetés szövegébe, mennyire unhatta már az XYZ és ABC-t ismerők seregeit, akik egyébként nem tudtak lóft se.

  6. tamasrev február 3, 2013 10:42 du.

    Hm, most látom, hogy az integer nem tud körbefordulni, mert annyiszor nem hívódik. Így viszont, mivel i és j is volatile, azt tippelem, hogy i>=j.

  7. Kofa február 3, 2013 11:17 du.

    Szerintem mind igaz.
    Az olvasó szál futhat az mindkét increment futása után, ekkor egyenlőek.
    Futhat i++ után, j++ előtt, ekkor i>j.
    Végül előfordulhat, hogy i-t kiolvasta, felfüggesztődik, párszor megfut a növelés, és az ezután kiolvasott j értéke magasabb lesz, mint a korábban kiolvasott j.

    A tippem az volt, hogy a JLS-ből vetted, és ezt azóta ellenőriztem is. 🙂

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s

%d blogger ezt kedveli: