Tikrintas rakinimas

Tikrintas rakinimas – paplitusi sinchronizavimo klaidų grupė kuriant naują objektą prireikus daugelio gijų aplinkoje.

Problema redaguoti

Š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.

Vienąkart tikrinto rakinimo klaida redaguoti

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 kintamajam a tos srities reikš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.

Dukart tikrinto rakinimo klaida redaguoti

Kai kurie programuotojai mano, jog vienąkart 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 sinchronizuoti visą konstrukciją, nors tai ir sąlygoja lėtesnį darbą:

synchronized (this)
  {
    if (a==null)
    a = new MusuObjektas();
  }

Literatūra redaguoti