Java Memory Model bilan tanishuv
Java Memory Model (JMM) Java muhitidagi iplarning harakatini tasvirlaydi. Pamyat modeli - Java tilining semantikasi qismi bo'lib, dasturchi nimaga tayanishi va nimaga tayanmasligi kerakligini bildiradi, maxsus bir Java mashinasida emas, balki Java umuman uchun dastur yaratganda.
Java dastlabki pamyat modeli (shu jumladan “protokolokal pamyat”) 1995 yilda ishlab chiqilgan va muvaffaqiyatsiz deb hisoblanadi: ko'plab optimallashtirishlar xavfsizlik kafolatisiz amalga oshirish mumkin emas. Xususan, ko'p ipli “singleton”ni yozish uchun bir nechta variantlar mavjud:
- yoki har bir yakkalikka kirish (hatto ob'ekt uzoq vaqtdan beri yaratilgan bo'lsa ham, va hech narsa o'zgarmaydi) boshqa iplar bloklanishini chaqiradi;
- yoki ma'lum holatlarda tizim bino qilinmagan yakkalikni chiqaradi;
- yoki ma'lum holatlarda tizim ikki yakkalikni yaratadi;
- yoki konstruktsiya ma'lum bir mashinaning xususiyatlari bilan bog'liqdir.
Shuning uchun pamyat ishlash mexanizmi qayta ishlab chiqildi. 2005 yilda, Java 5 chiqarilishi bilan yangi yondashuv taqdim etildi, bu yana Java 14 chiqishi bilan yaxshilandi.
Yangi model uchta qoida asosida ishlaydi:
1-qoida: bir ipli dasturlar psevdotartibda amalga oshiriladi. Bu degani: haqiqiylikda protsessor bir nechta operatsiyalarni bir taktga bajarishi mumkin va ularni tartibini o'zgartirishi mumkin, ammo barcha ma'lumotlar o'rtasidagi bog'liqlar saqlanadi, shuning uchun harakat ketma-ketlikdan farq qilmaydi.
2-qoida: hech qayerdan kelmagan qiymatlar mavjud emas. Har qanday o'zgaruvchini o'qish (non-volatile long va double dan tashqari, ular uchun bu qoida bajarilmasligi mumkin) yoki default qiymatni (nol) yoki boshqa buyruq tomonidan yozilgan narsani chiqaradi.
Va 3-qoida: boshqa voqealar “qachonki avval” qat'iy qisman tartib nisbatida bog'liq bo'lganda amalga oshiriladi (happens before).
Happens before
Leslie Lamport Happens before kontseptsiyasini o'ylab topdi. Bu qat'iy qisman tartib bilan atomar buyruqlar (har qanday ++ va -- ham emas) o'rtasida kiritilgan va “jismonan avval” anglatmaydi.
Bu shuni anglatadiki, ikkinchi buyruq birinchi tomonidan qilingan o'zgarishlar haqida "xabardor" bo'ladi.
Misol uchun, quyidagi operatsiyalar uchun biri boshqa oldin bajariladi:
Sinxronlashtirish va monitorlar:
- Monitorni qo'lga olish (metod lock, synchronized boshlanishi) va undan keyin bu ipda amalga oshiriladigan barcha narsa.
- Monitorni qaytarish (metod unlock, synchronized oxiri) va undan oldin bu ipda amalga oshiriladigan barcha narsa.
- Monitorni qaytarish va boshqa ip uni qo'lga olish.
Yozish va o'qish:
- Istalgan o'zgaruvchiga yozish va uni keyinchalik bir ipda o'qish.
- Volatile-o'zgaruvchiga yozishdan oldin bu ipda amalga oshirilgan hamma narsa va yozishning o'zi. Volatile-o'qishdan keyin bu ipda amalga oshiriladigan hamma narsa.
- Volatile-o'zgaruvchiga yozish va keyinchalik uni o'qish. Volatile -yozish xotira bilan monitorni qaytarish kabi o'zaro ta'sir qiladi, o'qish esa qo'lga olish kabi. Shuning uchun, agar bir ip volatile-o'zgaruvchiga yozgan bo'lsa va ikkinchisi buni aniqlasa, yozishdan oldin amalga oshirilgan hamma narsa o'qishdan keyin amalga oshiriladigan hamma narsadan oldin bajariladi; rasmga qarang.
Ob'ektni qo'llab-quvvatlash:
- Statik initsializatsiya va ob'ektlarning har qanday turdagi barcha amallar.
- Konstruktor ichida final-maydonlarga yozish va konstruktorlardan keyingi hamma narsa. Istisno sifatida - happens-before nisbat boshqa qoidalar bilan transitiv bog'lanmaydi va shuning uchun iplararo poyga chaqirishi mumkin.
- Ob'ekt bilan har qanday ishlash va finalize().
Iplarni qo'llab-quvvatlash:
- Ipni ishga tushirish va ipdagi har qanday kod.
- Ipga oid o'zgaruvchilarni nolga qaytarish va ipdagi har qanday kod.
- Ipdagi kod va join(); ipdagi kod va isAlive() == false.
- Ipni interrupt() va to'xtash holatini aniqlash.
Happens before ishining nozik tomonlari
Monitorni ozod qilish (releasing) happens-before sodir bo'ladi, bu esa monitorni olishdan oldin (acquiring). Bu haqida, aynan ozod qilishga, chiqishga emas, e'tiboringizni qaratishni unutmang, ya'ni wait foydalanishda xavfsizlik haqida tashvishlanishingizga hojat yo'q.
Keling, bu bilim bizga misolimizi o'zgartirishda qanday yordam berishini ko'rib chiqaylik. Bu holatda hammasi juda oddiy: tashqi tekshirishni olib tashlash va sinxronizatsiyani avvalgicha qoldirish kifoya. Endi ikkinchi ip barcha o'zgarishlarni ko'radi, chunki u monitorni faqat boshqa ip uni qo'yib yuborgandan keyin oladi. Va u uni qo'yib yubormaydi, hech narsa initsializatsiya qilmaguncha, biz hamma narsani birdan ko'ramiz, alohida emas:
public class Keeper {
private Data data = null;
public Data getData() {
synchronized(this) {
if(data == null) {
data = new Data();
}
}
return data;
}
}
Volatile oʻzgaruvchiga yozish oʻsha oʻzgaruvchini oʻqishdan oldin sodir boʻladi (happens-before). Biz kiritgan o'zgartirish, albatta, noto'g'ri emasligini to'g'irlaydi, lekin asl kodni yozgan odamni qaytaradi, u yerdan boshlagan - har safar blokirovka qilishga. Buni volatile kalit so'zi qutqarishi mumkin. Aslida, ko'rib chiqilayotgan gap shuni anglatadiki, volatile deb e'lon qilingan narsa o'qilganda, biz har doim dolzarb qiymatni olamiz.
Bundan tashqari, avval aytib o'tganimdek, volatile maydonlari uchun yozish har doim (jumladan long va double) atomar operatsiya bo'ladi. Yana bir muhim nuqta: agar sizda boshqa narsalarga ishora qiluvchi volatile mavjudlik bo'lsa (masalan, massiv, List yoki boshqa biror sinf), unda doimo “yangiligi” faqat shu mavjudotning o'ziga bo'ladi, lekin unga kiradigan hamma narsaga emas.
Xo'sh, Double-locking qo'ylarga qaytaylik. Volatile yordamida holatni bunday tuzatish mumkin:
public class Keeper {
private volatile Data data = null;
public Data getData() {
if(data == null) {
synchronized(this) {
if(data == null) {
data = new Data();
}
}
}
return data;
}
}
Bu yerda ham blokirovka mavjud, lekin faqat data == null bo'lgan holatlarda. Qolgan holatlarni biz volatile read yordamida filtrlab chiqamiz. To'g'riligiga volatile store happens-before volatile read kafolati bilan erishiladi va konstruktor ichida sodir bo'lgan barcha amallar uchun maydon qiymatini o'qiydigan kishi aniq ko'rinadi.
GO TO FULL VERSION