Aparat xotiraning arxitekturasi
Hozirgacha yani zamonaviy apparat xotiraning arxitekturasi Java xotira modelidan farqli. Shu sababli, apparat arxitekturani tushunish muhim, ta'kidlaymanki, Java model u bilan qanday ishlashini bilish kerak. Ushbu bo'limda umumiy apparat xotira arxitekturasi ko'rsatiladi, keyingi bo'limda esa Java qanday ishlashi tushuntiriladi.
Bu zamonaviy kompyuterning soddalashgan apparat arxitekturasi:
Hozirgi kunda kompyuterlarning 2 yoki undan ko'p protsessorlari borligi normaga aylangan. Baʼzilari bir necha yadroli ham bo'lishi mumkin. Shunday kompyuterlarda bir vaqtning o'zida bir nechta oqimlarni bajarish mumkin. Har bir protsessor yadrosi bir vaqtning o'zida bir oqimni ishlatishi mumkin. Bu degani, har qanday Java dastur avvaldan ko'p oqimli hisoblanadi va sizning dasturingizda har bir protsessor yadrosida bir vaqtda bitta oqim ishga tushirilishi mumkinligini anglatadi.
Protsessor yadrosi registrlar to'plamini o'z ichiga oladi, ular uning xotirasida (yadro ichida) joylashgan. U registrdagi ma'lumotlar ustida amallarni bajaradi, bu esa kompyuterning asosiy xotirasida (RAM) joylashgan ma'lumotlarga qaraganda ancha tez bajaradi. Bu protsessor bu registrlarga qulayroq va tezroq kirish imkoniga ega ekanligi bilan izohlanadi.
Har qanday CPU ham o'z kesh xotira qatlami bo'lishi mumkin. Ko'pgina zamonaviy protsessorlar uni o'z ichiga oladi. CPU kesh xotirasiga asosiy xotiraga qaraganda ancha tez kirish mumkin, lekin ichki registrlarga qaraganda uncha tez emas. Kesh xotiraga kirish tezligi odatda asosiy xotira va ichki registrlarga kirish tezliklari orasida bo'ladi.
Bundan tashqari, protsessorlarda ko'p darajali kesh mavjud. Ammo bu Java xotira modeli va apparat xotira o'rtasidagi aloqani tushunish uchun juda dolzarb emas. Muhimi, protsessorlar muayyan darajadagi kesh xotirasiga ega bo'lishi mumkinligini bilish kerak.
Har qanday kompyuter, shuningdek, RAM (asosiy xotira)ni o'z ichiga oladi. Hamma yadro asosiy xotiraga kirishi mumkin. Asosiy xotira odatda protsessorlarning kesh xotirasidan ancha katta hajmda bo'ladi.
Protsessorga asosiy xotiraga kirish zarur bo'lganda, u xotiraning bir qismini kesh xotirasiga yuklaydi. U shuningdek ma'lumotlarning bir qismini keshdan ichki registrlarga yuklashi va keyinchalik ular ustida amallar bajarishi mumkin. CPU natijani yana asosiy xotiraga qaytarib yozishga muhtoj bo'lganda, u ma'lumotlarni ichki registridan kesh xotirasiga yuklaydi va oxir-oqibat asosiy xotiraga ham.
Keshda saqlangan ma'lumotlar, odatda, protsessorga keshda yana biror narsa saqlash zarurati tug'ilganda asosiy xotiraga qayta yuklanadi. Kesh o'z xotirasini tozalash va bir vaqtning o'zida ma'lumotlarni yozish imkoniga ega. Protsessor har safar yangilanish paytida to'liq keshni o'qishi yoki yozishi shart emas. Odatda, kesh kichik xotira bloklari bilan yangilanadi, ular "kesh qatori" deyiladi. Bitta yoki bir necha "kesh qatori" kesh xotiraga yuklanishi mumkin va bitta yoki undan ortiq kesh qatori yana asosiy xotiraga tushirilishi mumkin.
Java xotira modeli va apparat xotira arxitekturasi qo'shilishi
Aytib o'tilganidek, Java xotira modeli va apparat xotira arxitekturasi farqli. Aparat arxitekturasi oqimning steklari va heapni (heap) ajratmaydi. O'rnatilgan apparatda oqimning steki va HEAP (heap) asosiy xotirada joylashadi.
Oqimning steklari va heapning qismlari vaqti-vaqti bilan CPU keshlarida va ichki registrlarda saqlanishi mumkin. Bu diagrammada ko'rsatilgan:
Obyektlar va o'zgaruvchilar kompyuterning turli xotira sohalarida saqlanishi mumkin bo'lganida, ma'lum muammolar yuzaga kelishi mumkin. Mana ikkita asosiy muammo:
- Oqim umumiy o'zgaruvchilar ustida qilgan o'zgarishlarini ko'rish.
- Umumiy o'zgaruvchilarni o'qish, tekshirish va yozishda yaratilgan raqobat holati.
Ushbu ikkala muammoni quyida tushuntirib beraman.
Umumiy obyektlarni ko'rish
Agar ikki yoki undan ortiq oqim obyektdan kerakli volatile-bayoni yoki sinxronizatsiyasiz foydalansa, bir oqim tomonidan qilingan umumiy obyekt o'zgarishlari boshqa oqimlar uchun ko'rinmas bo'lishi mumkin.
Tasavvur qiling, umumiy obyekt dastlab asosiy xotirada saqlangan. CPUda ishlayotgan oqim umumiy ob'ektni CPUning keshiga yuklaydi. U erda u ob'ektni o'zgartiradi. CPU keshini asosiy xotiraga yuklamagungacha, umumiy ob'ektning o'zgartirilgan versiyasi boshqa CPUda ishlayotgan oqimlar uchun ko'rinmaydi. Shu tarzda, har bir oqim o'zining umumiy obyekt nusxasini olishi mumkin, har bir nusxa har bir CPU keshida saqlanadi.
Quyidagi diagramma ushbu holatni ko'rsatadi. Qaysidir oqim, chap CPUda ishlayotgan umumiy obyektni keshiga yuklaydi va count o'zgaruvchisining qiymatini 2 ga o'zgartiradi. Bu o'zgartirish boshqa CPUda ishlayotgan oqimlar uchun ko'rinmas, chunki count uchun yangilanish hali asosiy xotiraga qayta yuklanmagan.
Ushbu muammoni hal qilish uchun, siz volatile kalit so'zidan foydalangan holda o'zgaruvchini e'lon qilishingiz mumkin. Bu berilgan o'zgaruvchining asosiy xotiradan bevosita o'qilishini va har safar yangilanganda asosiy xotiraga qayta yozilishini ta'minlashi mumkin.
Raqobat holati (race condition)
Agar ikki yoki undan ortiq oqim bir xil obyektni birgalikda ishlatsa va bir nechta oqimlar ushbu umumiy obyektning o'zgaruvchilarini yangilasa, raqobat holati yuzaga kelishi mumkin.
Tasavvur qiling, A oqimi umumiy obyekt o'zgaruvchisi countni o'z protsessorining keshiga o'qiydi. Tasavvur qiling, B oqimi ham ayni ishni qiladi, lekin boshqa protsessorning keshida. Endi A oqimi count o'zgaruvchisiga 1 qo'shadi va B oqimi ham ayni ishni qiladi. Endi o'zgaruvchi ikkala protsessorning keshi uchun alohida-alohida +1 ga oshgan.
Agar bu ortishlar ketma-ket amalga oshirilganida edi, count o'zgaruvchisi ikki marta ko'paygan bo'lar edi va asosiy xotiraga (asl qiymat + 2) yozilgan bo'lardi.
Biroq, ikkita ortish tegishli sinxronizatsiyasiz bir vaqtning o'zida bajarildi. Ushbu oqimlardan qaysi biri (A yoki B) countning o'zgartirilgan versiyasini asosiy xotiraga yozsa ham, oxirgi qiymat asl qiymatdan faqat 1 ga ko'proq bo'ladi, ikki ortish bo'lsa-da.
Quyidagi diagramma yuqorida tavsiflangan raqobat holati muammosini ko'rsatadi:
Ushbu muammoni hal qilish uchun Java sinxronlashtirilgan blokdan foydalanishingiz mumkin. Sinxronlashtirilgan blok ma'lum bir kodning kritik bo'limiga har doim bir vaqtda faqat bitta oqim kiritilishini ta'minlaydi.
Sinxronlashtirilgan bloklar shuningdek, sinxronlashtirilgan blok ichida kirilgan barcha o'zgaruvchilar asosiy xotiradan o'qilishini ta'minlaydi va oqim sinxronlashtirilgan blokdan chiqishda barcha yangilangan o'zgaruvchilar yana asosiy xotiraga qayta yuklanadi, bu o'zgaruvchi volatile yoki yo'qmi farqi yo'q.
GO TO FULL VERSION