Suoritusjärjestys säikeissä
Kirjoittanut J-P Julkaistu 9.2.2009
Kun ohjelman tulee toimia useassa säikeessä, on kriittisten koodilohkojen synkronointi avainasemassa toimivan järjestelmän aikaansaamisessa. Synkronointi ei kuitenkaan aina ole niin helppoa kuin, mitä aluksi voisi kuvitella ja synkronointi virheiden metsästäminen on usein varsin työlästä puuhaa. Ongelmia aiheuttavien ohjelmarakenteiden tunnistamisesta on kuitenkin merkittävää apua virheiden ennaltaehkäisyssä kuin niiden jäljityksessäkin.
Hieman vähemmän tunnettu säikeiden ominaisuus Javassa on, että eri säikeet eivät välttämättä saa tietoa muuttujan arvon muuttumisesta samassa järjestyksessä. Tämä tarkoittaa sitä, että muuttujat, joiden arvoa käsitellään useammasta säikeestä eivät voi luottaa siihen, että muuttujat asetettaisiin aina samassa järjestyksessä.
Seuraavan koodin voisi olevan turvallista:
public class NotSoSafe { private int arvo; private boolean asetettu=false; public synchronized setArvo(int arvo) { this.arvo = arvo; this.asetettu=true; } public int tryGetArvo() throws Exception { if (asetettu) return arvo; else throw new Exception( "Arvoa ei ole vielä asetettu"); } }
Kaikkihan on kunnossa eikö totta? setArvo on synkronoitu ja asetettu-muuttuja saa arvon true vasta kun arvo -muuttuja on asetettu. Näin ollenhan tryGetArvo aiheuttaa aina poikkeuksen jos setArvo -metodia ei ole kutsuttu.
Valitettavasti ei. Eri säikeet voivat muuttaa muuttujien arvoja eri järjestyksessä. Huonolla tuurilla, kun kuun asento on oikea, säie josta kutsumme tryGetValue()-metodia on muuttanut asetettu-muuttujan arvoon true, mutta ei ole vaihtanut arvo-muuttujan arvoa. Näin ollen metodin kutsuja saa virheellisen arvon eikä poikkeusta.
Ongelma voidaan korjata synkronoimalla tryGetArvo() metodi samalla lukolla kuin setArvo:
... public synchronized tryGetValue() throws Exception ...



