Tikrintas rakinimas
Straipsnis iš Vikipedijos, laisvosios enciklopedijos.
Tikrintas rakinimas – paplitusi sinchronizavimo klaidų grupė kuriant naują objektą prireikus daugelio gijų aplinkoje.
Turinys |
[taisyti] Problema
Ši klaida pasitaiko kuomet kokio nors ilgai kuriamo, neaišku ar prireiksiančio objekto reikšmė yra null, kol to objekto iš tiesų neprireikia. Jei vienu metu kodą vykdo daug gijų, null reikšmę gali vienu metu aptikti kelios gijos, kurios be reikalo sukurs ne vieną, o kelis objekto egzempliorius. Pavyzdyje
if (a==null) a = new MusuObjektas();
gali būti sukurti keli MusuObjektas egzemplioriai (a priskirtas liks paskutinis sukurtas). Mažų mažiausiai, tai neprotingai naudojami kompiuterio resursai, tačiau kai kuriais atvejais (pavyzdžiui, jei kuriamas objektas pats registruojasi kokiose nors lentelėse ir ten paskui lieka) toks daugelio egzempliorių kūrimas gali būti apskritai neleistinas.
[taisyti] Vienąkart tikrinto rakinimo klaida
Kadangi gijų sinchronizavimas yra brangi operacija, programuotojai neretai užrašo problemos sprendimą kaip
if (a==null) { synchronized (this) { a = new MusuObjektas(); } }
Šis kodas neveikia teisingai. Šiuo atvejų naujas objektas sukuriamas ir a reikšmė priskiriama sinchronizuotame sakinyje, kurį vienu metu gali vykdyti tik viena gija. Tačiau neretai sukompiliuotas kodas išskiria atminties sritį naujam objektui, priskiria kintamąjam a tos srities reišmę, ir tik tada pradeda vykdyti objektą inicializuojantį konstruktorių. Viena iš gijų gali gauti nenuliui lygią a reikšmę, rodančią į tik pusiau sukonstruotą objektą, kurio metodų kvietimai greičiausiai bus lydimi netikėtų veiksmų bei klaidų. Nepadeda ir a deklaravimas lakiu kintamuoju.
[taisyti] Dukart tikrinto rakinimo klaida
Kai kurie programuotojai mano, jog vienakart tikrinto rakinimo klaidą galima ištaisyti įvedus pakartotiną tikrinimą jau sinchronizuotoje dalyje:
if (a==null) { synchronized (this) { if (a == null) a = new MusuObjektas(); } }
Tai nieko iš esmės nekeičia – programa ir toliau dirba neteisingai. Be to, neteisingas darbas pasireiškia tik labai specifinėmis atsitiktinėmis aplinkybėmis, todėl net ir tikrai apie jį žinant, atkurti nėra paprasta.
Nors žinoma daug įvairių bandymų dar kitaip taisyti tikrinto rakinimo klaidas, dauguma jų nėra teisingi. Paprasčiausia sinchronzuoti visą konstrukciją, nors tai ir sąlygoje lėtesnį darbą:
synchronized (this) { if (a==null) a = new MusuObjektas(); }
[taisyti] Literatūra
- P.Hagar. Double-checked locking and the Singleton pattern (anglų kalba).