قبل قراءة هذه المقالة ، يمكنك أولاً قراءة " مقدمة واستخدام الحزمة الذرية Multithed Multithed Java " للتعرف على المحتوى ذي الصلة للحزمة الذرية.
1. ما هو الذرية؟
كلمة Atomic لها علاقة بالذرات ، والتي كانت تعتبر ذات يوم وحدة أصغر مسألة. ذري في الكمبيوتر يعني أنه لا يمكن تقسيمه إلى عدة أجزاء. إذا تم اعتبار جزء من الكود ذريًا ، فهذا يعني أنه لا يمكن مقاطعة الكود أثناء التنفيذ. بشكل عام ، يتم توفير الإرشادات الذرية بواسطة الأجهزة ويتم توفيرها بواسطة البرامج لتنفيذ الأساليب الذرية (لن يتم مقاطعة مؤشر ترابط بعد إدخال الطريقة حتى يكتمل تنفيذها)
على منصة X86 ، توفر وحدة المعالجة المركزية وسيلة لقفل الحافلة أثناء تنفيذ التعليمات. هناك Lead #Hlockpin على رقاقة وحدة المعالجة المركزية. إذا تمت إضافة البادئة "قفل" إلى تعليمات في برنامج لغة التجميع ، فإن رمز آلة التجميع سيؤدي إلى خفض وحدة المعالجة المركزية من إمكانات #HlockPin عند تنفيذ هذه التعليمات ، وإطلاقها حتى نهاية هذه التعليمات ، وبالتالي قفل الحافلة. وبهذه الطريقة ، لا تستطيع وحدات المعالجة المركزية الأخرى على نفس الحافلة الوصول إلى الذاكرة من خلال الحافلة في الوقت الحالي ، مما يضمن ذرة هذه التعليمات في بيئة متعددة المعالجات.
2. المتغيرات الذرية في java.util.concurrent
سواء كانت مباشرة أو غير مباشرة ، فإن جميع الفئات تقريبًا في حزمة java.util.concurrent تستخدم المتغيرات الذرية ، وليس التزامن. تستخدم فئات مثل ConcurrentLinkedQueue أيضًا المتغيرات الذرية لتنفيذ خوارزمية خالية من الانتظار مباشرة ، في حين تستخدم فئات مثل ConcurrenthashMap إعادة إدخالها عند الحاجة. REENTRANTLOCK ثم يستخدم المتغيرات الذرية للحفاظ على قائمة انتظار الخيط في انتظار القفل.
بدون تحسينات JVM في JDK5.0 ، لن يتم إنشاء هذه الفئات ، والتي تعرض (لمكتبة الفصل ، وليس فئة المستخدم) للوصول إلى بدائل التزامن على مستوى الأجهزة. الفئات المتغيرة الذرية والفئات الأخرى في java.util.concurrent ثم تعرض هذه الوظائف لفئة المستخدم
الفئة الذرية من java.util.concurrent.atomic
توفر هذه الحزمة مجموعة من الفصول الذرية. ميزةها الأساسية هي أنه في بيئة متعددة الخيوط ، عندما تنفذ مؤشرات ترابط متعددة الطرق الواردة في حالات هذه الفئات في نفس الوقت ، يكون حصريًا ، أي عندما يدخل مؤشر ترابط في الطريقة وينفذ التعليمات الموجودة فيه ، فلن تتم مقاطعتها بواسطة مؤشرات ترابط أخرى ، وتكون مؤشرات الترابط الأخرى مثل قفلات الدوران. حتى يتم تنفيذ الطريقة ، سيقوم JVM بتحديد موضوع آخر من قائمة انتظار الانتظار للدخول. هذا مجرد فهم منطقي. في الواقع ، يتم تنفيذها بمساعدة تعليمات الأجهزة ذات الصلة ولن تمنع مؤشرات الترابط (أو يتم حظرها فقط على مستوى الأجهزة). يمكن تقسيم الفصول إلى 4 مجموعات
Atomicboolean ، Atomicinteger ، Atomiclong ، AtomicReference
Atomicintegerarray ، Atomiclongarray
Atomiclongfieldupdater ، Atomicintegerfieldupdater ، AtomicReferenceFieldupdater
AtomicMarkablereference ، AtomicStampedReference ، AtomicReferenceArray
من بينها ، Atomicboolean ، Atomicinteger ، Atomiclong ، AtomicReference متشابهة.
بادئ ذي بدء ، Atomicboolean ، Atomicinteger ، Atomiclong ، AtomicReference APIs متشابهة: خذ مثالًا على AtomicReference
قم بإنشاء مكدس آمن مؤشر ترابط مع AtomicReference
الطبقة العامة LinkedStack <T> {private AtomicReference <Node <T >> stacks = new AtomicReference <Node <T> () ؛ Public T Push (t e) {node <t> oldnode ، newNode ؛ بينما (صحيح) {// المعالجة هنا مميزة للغاية ، ويجب أن يكون الأمر كذلك. oldnode = stacks.get () ؛ newNode = new node <t> (e ، oldnode) ؛ if (stacks.compareanset (oldnode ، newNode)) {return e ؛}}} public t pop () {node <t> oldnode ، newnode ؛ (stacks.compareanset (Oldnode ، newNode)) {return oldnode.object ؛}} عقدة الفئة النهائية الثابتة الخاصة <T> {private t object ؛ node private <t> next ؛ node private (t object ، node <t> next) {this.object = object ؛ this.next = next ؛}}}}}}}}}}}}}ثم ركز على التحديث الذري للحقل.
AtomicIntegerFieldupdater <T>/Atomiclongfieldupdater <T>/AtomicReferenceFieldupdater <T ، V> هي قيمة الحقل على أساس الانعكاس.
واجهة برمجة التطبيقات المقابلة بسيطة للغاية ، ولكن لديها أيضًا بعض القيود.
(1) يجب أن يكون الحقل من نوع متقلبة! ما هو المتقلبة؟ يرجى التحقق من " شرح مفصل للكلمات الرئيسية المتطايرة في جافا "
(2) يتوافق نوع وصف الحقل (المعدل العام/المحمي/الافتراضي/الخاص) مع العلاقة بين المتصل وحقل كائن العملية. وهذا يعني أن المتصل يمكنه تشغيل حقل الكائن مباشرة ، ثم يعكس ويؤدي العمليات الذرية. ومع ذلك ، بالنسبة لحقول الفئة الأم ، لا يمكن تشغيل الفئة الفرعية مباشرة ، على الرغم من أن الفئة الفرعية يمكنها الوصول إلى حقول الفئة الأصل.
(3) يمكن أن يكون متغير مثيل فقط ، وليس متغير فئة ، أي أنه لا يمكن إضافة كلمات رئيسية ثابتة.
(4) لا يمكن تعديل المتغيرات إلا ، ولا يمكن تحويلها إلى المتغيرات النهائية ، لأن دلالات النهائي غير معدلة. في الواقع ، لا يمكن أن توجد دلالات الصراع النهائي والمتقلب ، وهاتين الكلمة الرئيسية في نفس الوقت.
(5) بالنسبة لـ AtomicIntegerfieldupdater و Atomiclongfieldupdater ، يمكنهم فقط تعديل حقول من النوع int/طويل ، ولا يمكنهم تعديل نوع التفاف (عدد صحيح/طويل). إذا كنت ترغب في تعديل نوع التغليف ، فأنت بحاجة إلى استخدام AtomicReferenceFieldupDater.
تم وصف طريقة التشغيل في المثال التالي.
استيراد java.util.concurrent.atomic.atomicintegerfieldupdater ؛ الطبقة العامة atomicintegerfieldupdaterdemo {class demodata {publatile folatile int value1 = 1 ؛ folatile int value2 = 2 ؛ protected folatile int value3 = 3 ؛ fieldName) {return atomicintegerfieldupdater.newupdater (demodata.class ، fieldName) ؛} void doit () {demodata data = new demodata () ؛ system.out.println ("1 ==>"+getUpdater ("value1"). "+getUpdater (" value2 "). GexrementAndget (data)) ؛ system.out.println (" 2 ==> "+getUpdater (" value3 "). delationandget (data))) {AtomicIntegerfieldupdaterdemo Demo = new AtomicIntegerFieldupDaterDemo () ؛ demo.doit () ؛}}في المثال أعلاه ، لا يمكن مرئي الحقل القيمة 3/value4 من demodata لفئة AtomicIntegerFieldupDaterDemo ، لذلك لا يمكن تعديل قيمتها مباشرة من خلال الانعكاس.
يمكن لزوج من <كائن ، منطقية> الموصوفة بواسطة فئة AtomIcMarkAblereference تعديل قيمة الكائن أو منطقية. بنية البيانات هذه أكثر فائدة في بعض ذاكرة التخزين المؤقت أو أوصاف الحالة. يمكن لهذا الهيكل تحسين الإنتاجية بشكل فعال عند تعديل الكائن/منطقية بشكل فردي أو في وقت واحد.
تحافظ فئة AtomicStampedReference على مراجع الكائنات مع "أعلام" عدد صحيح ويمكن تحديثها ذريًا. بالمقارنة مع <bourt ، boolean> من فئة AtomIcMarkAlterference ، تحافظ AtomicStampedReference على بنية بيانات مماثلة لـ <كائن ، int> ، وهو في الواقع عدد متزامن للكائنات (المراجع). ولكن على عكس AtomicInteger ، يمكن أن يحمل بنية البيانات مرجع كائن ويمكنه إجراء العمليات الذرية على هذا الكائن والعد في نفس الوقت.
سيتم ذكر "مشكلة ABA" في نهاية هذه المقالة ، و AtomIcMarkablereference/AtomicStampedReference مفيدة في حل "مشكلة ABA".
ثالثا. دور الذرية
هذا يتيح تشغيل البيانات المفردة من ذرية
قم ببناء رمز معقد خالي من الحظر باستخدام الفئات الذرية
يعتبر الوصول إلى متغيرين ذريين أو أكثر (أو إجراء عمليتين أو أكثر على متغير ذري واحد) بشكل عام يتطلب التزامن بحيث يمكن استخدام هذه العمليات كوحدة ذرية.
لا قفل ولا خوارزمية انتظار
تسمى خوارزميات التزامن القائمة على CAS (المقارنة) خوارزميات خالية من القفل لأن المواضيع لا يجب أن تنتظر القفل بعد الآن (تسمى أحيانًا mutexes أو الأجزاء الحرجة ، اعتمادًا على مصطلحات منصة الخيط). ما إذا كانت عملية CAS تنجح أو تفشل ، في كلتا الحالتين ، يتم الانتهاء منها في غضون وقت يمكن التنبؤ به. إذا فشلت CAS ، يمكن للمتصل إعادة تشغيل عملية CAS أو أخذ عمليات مناسبة أخرى.
إذا استمر كل مؤشر ترابط في العمل عند تأخير مؤشرات الترابط الأخرى (أو حتى فشل) ، فيمكن القول أن الخوارزمية خالية من الانتظار. في المقابل ، تتطلب الخوارزمية الخالية من القفل أن يقوم مؤشر ترابط معين فقط بإجراء العملية. (يتمثل تعريف آخر لعدم الانتظار في التأكد من أن كل مؤشر ترابط يحسب بشكل صحيح عملياته الخاصة في خطواته المحدودة ، بغض النظر عن العمليات أو التوقيت أو التقاطع أو سرعة مؤشرات الترابط الأخرى. يمكن أن يكون هذا الحد وظيفة لعدد المواضيع في النظام ؛ على سبيل المثال ، على سبيل المثال ، سيستفيد كل سلسلة من المواضيع.
على مدار الخمسة عشر عامًا الماضية ، أجرى الناس أبحاثًا مكثفة حول خوارزميات خالية من الانتظار وخالية من القفل (المعروفة أيضًا باسم الخوارزميات غير المحظورة) ، وقد اكتشف الكثير من الأشخاص خوارزميات غير محظورة في هياكل البيانات العامة. تستخدم خوارزميات عدم الحظر على نطاق واسع في نظام التشغيل ومستوى JVM ، حيث تقوم بمهام مثل الترابط وجدولة العملية. على الرغم من أن تنفيذها أكثر تعقيدًا ، إلا أن لديهم العديد من المزايا على الخوارزميات البديلة القائمة على القفل: يمكنهم تجنب المخاطر مثل انعكاس الأولوية والتمتزل ، إلا أن المنافسة أرخص ، ويحدث التنسيق على مستوى دقة ، مما يسمح بدرجة أعلى من التوازي ، وما إلى ذلك.
شائع:
عداد عدم الحظر
المكدس غير المحظور ConcurrentStack
القائمة المرتبطة غير المحظورة concurrentLinkedqueue
أسئلة ABA:
لأنه قبل تغيير V ، يسأل CAS بشكل أساسي "ما إذا كانت قيمة V لا تزال" ، قبل القراءة V لأول مرة وأداء عمليات CAS على V ، وتغيير القيمة من A إلى B ثم تعود إلى A سوف تخلط بين الخوارزمية المستندة إلى CAS. في هذه الحالة ، ستنجح عملية CAS ، ولكن في بعض الحالات قد لا تكون النتيجة ما توقعته. يُطلق على هذا النوع من المشكلات مشكلة ABA ، والتي عادة ما يتم التعامل معها عن طريق ربط علامة أو رقم إصدار مع كل قيمة ليتم تنفيذها في عملية CAS وتحديث القيم والعلامات الذرية. تدعم فئة AtomicStampedReference هذه الطريقة.
لخص
ما ورد أعلاه هو كل التفسير التفصيلي لهذه المقالة حول تشغيل المتغيرات الذرية والطبقات الذرية في حزمة ذرية متعددة الخيوط Java. آمل أن يكون ذلك مفيدًا للجميع. يمكن للأصدقاء المهتمين الاستمرار في الرجوع إلى هذا الموقع:
برمجة Java: قتاب متعدد الخيوط والتواصل بين المواضيع رمز بسيط
جافا متعدد الخيوط البرمجة مثال صغير يحاكي نظام موقف السيارات
مناقشة موجزة حول مزايا وأمثلة رمز لـ Java MultiThreading
إذا كانت هناك أي أوجه قصور ، فيرجى ترك رسالة لإشارةها.