يوفر المتغير المتطرف رؤية مؤشر الترابط ولا يضمن سلامة الخيط والذرية.
ما هي رؤية الموضوع:
توفر الأقفال ميزتين رئيسيتين: الاستبعاد المتبادل والرؤية. يعني الاستبعاد المتبادل أن مؤشر ترابط واحد فقط يمكنه الاحتفاظ بقفل معين في وقت واحد ، بحيث يمكن استخدام هذه الميزة لتنفيذ بروتوكول وصول منسق للبيانات المشتركة ، بحيث يمكن لخيط واحد فقط استخدام البيانات المشتركة في وقت واحد. تكون الرؤية أكثر تعقيدًا قليلاً ، ويجب أن تضمن أن التغييرات في البيانات المشتركة قبل إطلاق القفل مرئية لخيط آخر يكتسب لاحقًا القفل - دون ضمان الرؤية هذا الذي توفره آلية التزامن ، قد تكون المتغيرات المشتركة التي يرىها الخيط معدلًا مسبقًا أو غير متناسق ، مما سيؤدي إلى العديد من المشكلات الخطيرة.
انظر دلالات المتقلبة :
يتساقط التقلب مع ضعف التنفيذ المتزامن ، مما يعني أن الأدوات المتطايرة التي تنفذ دلالات متزامنة ، ولكن ليس لها آلية قفل. إنه يضمن أن تحديثات الحقل المتقلب إبلاغ المواضيع الأخرى بطريقة يمكن التنبؤ بها.
يحتوي المتقلبة على الدلالات التالية:
(1) لن يعيد نموذج تخزين Java ترتيب عمليات تعليمات Valatile: وهذا يضمن تنفيذ العمليات على المتغيرات المتطايرة بالترتيب الذي تظهر به التعليمات.
(2) لن يتم تخزين المتغير المتطاير في السجل (فقط المواضيع مرئية) أو أماكن أخرى غير مرئية لوحدة المعالجة المركزية. تتم دائمًا قراءة نتيجة المتغير المتطاير من الذاكرة الرئيسية في كل مرة. بمعنى آخر ، لتعديل المتغير المتطاير ، تكون مؤشرات الترابط الأخرى مرئية دائمًا ، ولا تستخدم متغيرات داخل مكدس الخيط. وهذا هو ، في القانون الذي يحدث ، بعد كتابة متغير فالياتيلي ، يمكن فهم أي عملية قراءة لاحقة لترى نتيجة عملية الكتابة هذه.
على الرغم من أن خصائص المتغير المتطاير جيد ، إلا أن المتقلبة لا يمكن أن تضمن سلامة الخيط. وهذا يعني ، أن تشغيل الحقل المتطاير ليس ذريًا. يمكن أن يضمن المتغير المتطاير فقط الرؤية (يمكن لخيوط أخرى فهم النتائج بعد رؤية هذا التغيير بعد تعديل مؤشر ترابط واحد). لضمان الذرة ، يمكنك قفلها حتى الآن!
مبادئ استخدام المتقلبة:
ثلاثة مبادئ لتطبيق المتغيرات المتقلبة:
(1) لا تعتمد متغيرات الكتابة على قيمة هذا المتغير ، أو فقط مؤشر ترابط واحد يعدل هذا المتغير
(2) لا تحتاج حالة المتغير إلى المشاركة في القيود الثابتة مع المتغيرات الأخرى
(3) لا تحتاج متغيرات الوصول إلى قفلها
في الواقع ، تشير هذه الشروط إلى أن هذه القيم الصحيحة التي يمكن كتابتها إلى المتغير المتقلبة مستقلة عن حالة أي برنامج ، بما في ذلك الحالة الحالية للمتغير.
تمنع حدود الشرط الأول المتغير المتقلبة من استخدامه كضكانة آمنة لخيط الخيط. على الرغم من أن العملية الإضافية (X ++) تبدو وكأنها عملية منفصلة ، إلا أنها في الواقع عملية مشتركة تتكون من سلسلة من العمليات المعدلة القراءة التي يجب أن يتم تنفيذها ذريًا ، ولا يمكن أن توفر المتقلبة الخصائص الذرية اللازمة. يتطلب تنفيذ العملية الصحيحة الحفاظ على قيمة X ثابتة أثناء العملية ، وهو أمر غير ممكن مع المتغير المتطاير. (ومع ذلك ، إذا تم ضبط القيمة لتكون مكتوبة فقط من موضوع واحد ، يمكن تجاهل الشرط الأول.)
تتعارض معظم مواقف البرمجة مع إحدى هذه الشروط الثلاثة ، مما يجعل المتغير المتقلبة لا ينطبق عالميًا على سلامة الخيط كما هو متزامن. يوضح القائمة 1 فئة النطاق العددي غير الآمن. أنه يحتوي على ثابت - الحد الأدنى دائمًا أقل من أو يساوي الحد الأعلى.
استخدم متطايرة بشكل صحيح:
الوضع رقم 1: أعلام الحالة
ربما يكون مواصفات تنفيذ المتغير المتطاير هو ببساطة استخدام علامة حالة منطقية للإشارة إلى أن حدثًا مهمًا لمرة واحدة قد حدث ، مثل إكمال التهيئة أو طلب التوقف.
تتضمن العديد من التطبيقات بنية تحكم في شكل "تنفيذ بعض الأعمال عندما لا يكون البرنامج جاهزًا للتوقف" ، كما هو موضح في القائمة 2:
قائمة 2. استخدم المتغير المتطاير كعلم الحالة
متقلبة المنطقية الإغلاق. ... الإغلاق public void () {letdownrequested = true ؛ )من المحتمل جدًا أن يتم استدعاء طريقة إيقاف التشغيل () من خارج الحلقة - أي في مؤشر ترابط آخر - لذلك يجب تنفيذ نوع من التزامن لضمان تنفيذ رؤية المتغير المطلوب إيقاف التشغيل بشكل صحيح. (قد يتم استدعاؤه من مستمع JMX ، مستمع عملية في واجهة المستخدم الرسومية ، من خلال RMI ، من خلال خدمة ويب ، إلخ). ومع ذلك ، فإن كتابة حلقة مع كتلة متزامنة أكثر إزعاجًا من الكتابة مع علامة الحالة المتطايرة الموضحة في القائمة 2. نظرًا لأن المتقلبة تبسيط الترميز ولا تعتمد أعلام الحالة على أي حالات أخرى داخل البرنامج ، فهي مناسبة جدًا للمتقلب هنا.
ميزة شائعة لهذا النوع من علامة الحالة هي أنه عادة ما يكون هناك انتقال واحد فقط ؛ يتم تحويل العلم المكتوب من الإغلاق من خطأ إلى صحيح ، ويتوقف البرنامج. يمكن تمديد هذا النمط إلى علامة حالة الانتقال للخلف والخلف ، ولكن لا يمكن تمديده إلا إذا لم يتم ملاحظة فترة الانتقال (من خطأ إلى صواب ، ثم إلى خطأ). بالإضافة إلى ذلك ، هناك حاجة إلى بعض آليات تحويل الحالة الذرية ، مثل المتغيرات الذرية.
الوضع رقم 2: منشور آمن لمرة واحدة
يمكن أن يؤدي عدم التزامن إلى رؤية غير قابلة للتحقيق ، مما يجعل من الصعب تحديد وقت كتابة مرجع كائن بدلاً من قيمة بدائية. في حالة عدم وجود تزامن ، قد تتم مواجهة قيمة محدثة يشار إليها كائن (كتبها مؤشر ترابط آخر) وتجعل القيمة القديمة لحالة ذلك الكائن في وقت واحد. (هذا هو السبب الجذري لمشكلة القفل الشهيرة التي يتم التحقق منها حيث تتم قراءة مراجع الكائنات دون المزامنة ، مما يؤدي إلى المشكلة التي قد ترى مرجعًا محدثًا ، ولكن لا تزال ترى كائنًا تم إنشاؤه بشكل غير مكتمل من خلال هذا المرجع).
تتمثل إحدى التقنيات لتنفيذ النشر الآمن للكائنات في تحديد مراجع الكائنات كنوع متقلبة. تعرض القائمة 3 مثالاً حيث يقوم مؤشر ترابط الخلفية بتحميل بعض البيانات من قاعدة البيانات أثناء بدء التشغيل. رموز أخرى ، عندما تكون قادرة على استخدام هذه البيانات ، تحقق مما إذا كان قد تم نشرها قبل الاستخدام.
سرد 3. باستخدام المتغير المتقلبة لإصدار آمن لمرة واحدة
Public Class BackgroundFloobleloader {public floolelble theflooble ؛ public void initinbackground () {// قم بالكثير من الأشياء theflooble = new flooble () ؛ // هذه هي الكتابة الوحيدة إلى الفئة العامة}} someotherclass {public void dowork () {بينما (صحيح) {// قم ببعض الأشياء ...// استخدم flooble ، ولكن فقط إذا كان جاهزًا إذا كان (floobleloader.thefloble! }}}إذا لم يكن المرجع theflooble نوعًا متقلبًا ، فسوف يحصل الكود الموجود في Dowork () على حدوث عدوى غير مكتملة عندما يكرر theflooble.
الشرط اللازم لهذا النمط هو أن الكائن المنشور يجب أن يكون آمنًا لخيط الخيط ، أو كائنًا غير قابل للتغيير صالح (يعني فعالة غير قابلة للتغيير أن حالة الكائن لن يتم تعديلها بعد النشر). تضمن مراجع النوع المتقلبة رؤية نموذج نشر الكائن ، ولكن هناك حاجة إلى التزامن إضافي إذا كانت حالة الكائن ستتغير بعد النشر.
النمط رقم 3: ملاحظة مستقلة
هناك طريقة بسيطة أخرى لاستخدام المتقلبة بأمان وهي "إطلاق" الملاحظات بانتظام للاستخدام الداخلي للبرنامج. على سبيل المثال ، لنفترض أن هناك مستشعر المحيط قادر على استشعار درجة الحرارة المحيطة. قد يقرأ مؤشر ترابط الخلفية المستشعر كل بضع ثوانٍ وتحديث المتغير المتطاير الذي يحتوي على المستند الحالي. بعد ذلك ، يمكن لخيوط أخرى قراءة هذا المتغير حتى يتمكنوا من رؤية أحدث قيمة درجة الحرارة في أي وقت.
تطبيق آخر يستخدم هذا الوضع هو جمع إحصائيات البرنامج. توضح القائمة 4 كيف تتذكر آلية المصادقة اسم المستخدم الذي تم تسجيل الدخول للمرة الأخيرة. كرر إشارة LASTUSER لنشر القيم لأجزاء أخرى من البرنامج.
قائمة 4. باستخدام المتغير المتقلب لنشر ملاحظات مستقلة متعددة
الطبقة العامة usermanager {public platile String Lastuser ؛ مصادقة منطقية عامة (مستخدم سلسلة ، كلمة مرور السلسلة) {boolean apport = passwordisvalid (المستخدم ، كلمة المرور) ؛ if (صالح) {user u = new user () ؛ ActiveUsers.Add (u) ؛ LASTUSER = المستخدم ؛ } إرجاع صالح ؛ }}هذا الوضع هو امتداد للوضع السابق ؛ نشر قيمة معينة للاستخدام في مكان آخر في البرنامج ، ولكن على عكس نشر حدث لمرة واحدة ، فهو سلسلة من الأحداث المستقلة. يتطلب هذا النمط أن تكون القيمة المنشورة صالحة وغير قابلة للتغيير - أي أن حالة القيمة لن تتغير بعد النشر. يجب أن يكون الرمز الذي يستخدم هذه القيمة واضحًا أن القيمة قد تتغير في أي وقت.
الوضع رقم 4: وضع "الفول المتطاير"
نمط الفاصوليا المتطايرة مناسب للأطر التي تستخدم جافابانز باعتبارها "هيكل الشرف". في نمط الفاصوليا المتطايرة ، يتم استخدام Javabeans كمجموعة من الحاويات مع خصائص مستقلة من طرق Getter و/أو Setter. المبدأ الأساسي لنمط الفاصوليا المتطايرة هو أن العديد من الأطر توفر حاويات لأصحاب البيانات المتطايرة (مثل httpsession) ، ولكن يجب أن تكون الكائنات الموضوعة في هذه الحاويات آمنة للمعلومات.
في وضع الفاصوليا المتطايرة ، يكون جميع أعضاء البيانات في جافابين من النوع المتقلبة ، ويجب أن تكون طرق getter و setter عادية للغاية - لا يمكن أن تحتوي على أي منطق باستثناء الحصول على أو تعيين خصائص مقابلة. بالإضافة إلى ذلك ، بالنسبة لأعضاء البيانات المشار إليها من قبل الكائن ، يجب أن يكون الكائن المشار إليه صالحًا وغير قابل للتغيير. (سيحظر هذا الخصائص ذات قيم الصفيف ، لأنه عندما يتم إعلان مرجع الصفيف على أنه متقلبة ، فإن المرجع فقط وليس الصفيف نفسه له دلالات متطايرة). بالنسبة لأي متغير متطاير ، لا يمكن أن تحتوي الثبات أو القيود على خصائص Javabean. تظهر الأمثلة في سرد 5 جافابانز التي تلتزم بنمط الفاصوليا المتطايرة:
الوضع رقم 4: وضع "الفول المتطاير"
ThereDSafe Public Class Person {private folatile string firstName ؛ سلسلة متطايرة خاصة. عصر int المتقلبة الخاصة ؛ السلسلة العامة getFirstName () {return firstName ؛ } السلسلة العامة getLastName () {return lastName ؛ } public int getage () {return Age ؛ } public void setFirstName (String firstName) {this.firstName = firstName ؛ } public void setLastName (String lastName) {this.lastname = lastName ؛ } public void setage (int age) {this.age = age ؛ }}الوضع المتقدم للمتقلبة
تغطي الأنماط الموضحة في الأقسام السابقة معظم حالات الاستخدام الأساسية ، واستخدام المتقلبة في هذه الأنماط مفيدة وبسيطة للغاية. يقدم هذا القسم وضعًا أكثر تقدماً يوفر فيه متقلبة مزايا الأداء أو التوسع.
الأنماط المتقدمة للتطبيقات المتقلبة هشة للغاية. لذلك ، يجب إثبات الافتراضات بعناية ، وهذه الأنماط مغلفة بشكل صارم لأنه حتى التغييرات الصغيرة جدًا يمكن أن تفسد الكود الخاص بك! وبالمثل ، فإن سبب استخدام حالة استخدام متقلبة أكثر تقدماً هو أنه يمكن أن يحسن الأداء ، مما يضمن أنك تحدد حقًا أنك بحاجة إلى تحقيق فائدة الأداء هذه قبل البدء في تطبيق الأنماط المتقدمة. هناك مقايضات حول هذه الأنماط ، أو التخلي عن قابلية القراءة أو الصيانة في مقابل الحصول على مكاسب الأداء المحتملة-إذا كنت لا تحتاج إلى تحسينات في الأداء (أو لا يمكنك إثبات أنك في حاجة إليها من خلال برنامج اختبار صارم) ، فمن المحتمل أن تكون صفقة سيئة لأنك ستفقد أموالًا أقل على الأرجح والحصول على شيء أقل مما تتخلى عنه.
الوضع رقم 5: استراتيجية قفل القراءة والكتابة مع انخفاض النفقات العامة
حتى الآن ، يجب أن تفهم أن المتقلبة غير قادر على تنفيذ العدادات. نظرًا لأن ++ X هو في الواقع مزيج بسيط من ثلاث عمليات (اقرأ ، أضف ، تخزين) ، إذا صادفت عدة مؤشرات ترابط لمحاولة إجراء عمليات تدريجية على العداد المتطاير في نفس الوقت ، فقد تضيع قيمتها المحدثة.
ومع ذلك ، إذا كانت عملية القراءة أكثر بكثير من عملية الكتابة ، فيمكنك استخدام قفل داخلي ومتغيرات متقلبة لتقليل النفقات العامة لمسار الكود العام. تستخدم عدادات آمنة مؤشرات الترابط الموضحة في القائمة 6 متزامنة لضمان أن العمليات الإضافية ذرية ومتقلب لضمان رؤية النتيجة الحالية. يمكن أن تحقق هذه الطريقة أداءً أفضل إذا لم تكن التحديثات متكررة ، لأن النفقات العامة لمسارات القراءة لا تنطوي فقط على عملية القراءة المتطايرة ، والتي عادة ما تكون أفضل من اكتساب اكتساب القفل الخالي من المنافسة.
قائمة 6. استخدم متطايرة ومزامنة لتحقيق "أقفال تكتسب القراءة المنخفضة"
ThereDsafe Public Class CheesyCounter {// توظف خدعة قفل القراءة الرخيصة // يجب أن تتم جميع العمليات المتطورة مع "هذا القفل". Public int getValue () {return value ؛ } synchronized int int () {return value ++ ؛ }}السبب في أن هذه التقنية تسمى "قفل الكتاب القراءة السفلي القراءة" هو أنك تستخدم آلية تزامن مختلفة لعمليات القراءة والكتابة. نظرًا لأن عملية الكتابة في هذا المثال تنتهك الشرط الأول لاستخدام المتقلبة ، فلا يمكن تنفيذ العداد بأمان مع متقلبة - يجب عليك استخدام قفل. ومع ذلك ، يمكنك استخدام عمليات القراءة في عمليات القراءة لضمان رؤية القيمة الحالية ، حتى تتمكن من استخدام الأقفال لأداء جميع التغييرات والقراءة فقط مع متقلبة. من بينها ، يتيح القفل فقط مؤشر ترابط واحد للوصول إلى القيمة في وقت واحد ، ويسمح المتقلبة بموضوعات مؤشرات ترابط متعددة بأداء عمليات القراءة. لذلك ، عند استخدام متقلبة للتأكد من قراءة مسار الكود ، يكون مشاركة أكثر من استخدام القفل لتنفيذ جميع مسارات التعليمات البرمجية - تمامًا مثل عملية القراءة والكتابة. ومع ذلك ، ضع في اعتبارك أن نقاط الضعف في هذا النموذج في الاعتبار: إذا كان التطبيق الأساسي لهذا النموذج هو أبعد من ذلك ، فسيصبح من الصعب للغاية الجمع بين هاتين آليتين المتزامنين المتنافسين.
حول إعادة ترتيب التعليمات وقاعدة الحدث قبل
1. دع إعادة الترتيب
تنص مواصفات لغة Java على أن مؤشر ترابط JVM يحافظ على دلالات متسلسلة داخليًا ، أي ، طالما أن النتيجة النهائية للبرنامج تعادل نتائجه في بيئة متتابعة صارمة ، قد لا يتماشى ترتيب تنفيذ التعليمات مع ترتيب الكود. يتم إعادة ترتيب هذه العملية بواسطة أمر. تتمثل أهمية إعادة ترتيب التعليمات في أن JVM يمكنه إعادة ترتيب تعليمات الجهاز بشكل مناسب وفقًا لخصائص المعالج (نظام ذاكرة التخزين المؤقت متعدد المستويات في وحدة المعالجة المركزية ، ومعالج متعدد النواة ، وما إلى ذلك) ، بحيث تكون تعليمات الجهاز أكثر تمشيا مع خصائص تنفيذ وحدة المعالجة المركزية وتعظيم أداء الماكينة.
يتمثل أبسط نموذج لتنفيذ البرنامج في التنفيذ بالترتيب الذي تظهر به التعليمات ، وهو مستقل عن وحدة المعالجة المركزية التي تنفذ التعليمات ، مما يضمن قابلية نقل التعليمات إلى أقصى حد. ويسمى المصطلح المهني لهذا النموذج نموذج الاتساق المتسلسل. ومع ذلك ، فإن أنظمة الكمبيوتر الحديثة والمعالجات لا تضمن ذلك (لأن التعيين الاصطناعي لا يمكن أن يضمن دائمًا الامتثال لخصائص معالجة وحدة المعالجة المركزية).
2. القاعدة قبل التبرز
يحتوي نموذج تخزين Java على مبدأ يحدث ، أي إذا أراد الإجراء B رؤية نتيجة التنفيذ لاتخاذ إجراء (بغض النظر عما إذا كان يتم تنفيذ A/B في نفس الموضوع) ، فيجب أن ترضي A/B العلاقة التي تحدث قبل.
قبل تقديم قاعدة SECT-Beorefore ، قدم مفهومًا: JMM Action (Java Memeory Model Action) ، تقوم Java بتخزين الإجراءات النموذجية. يتضمن الإجراء: قراءة وكتابة المتغيرات ، ومراقبة قفل وإصدار الأقفال ، و start () والانضمام (). سيتم ذكر القفل لاحقًا.
حدث قبل القواعد الكاملة:
(1) يحدث كل إجراء في نفس مؤشر الترابط قبل أي إجراء يظهر بعده.
(2) فتح شاشة يحدث قبل كل قفل لاحق على نفس الشاشة.
(3) اكتب عملية إلى الحقل المتقلب يحدث قبل كل عملية قراءة لاحقة لنفس الحقل.
(4) سوف تحدث دعوة إلى thread.start () قبل الإجراءات في مؤشر ترابط بدء التشغيل.
(5) جميع الإجراءات في مؤشر الترابط-يتم إجراء عمليات فحص على مؤشرات الترابط الأخرى لإنهاء هذا الموضوع أو العودة في thread.ojoin () أو thread.isalive () == false.
(6) يدعو مؤشر ترابط واحد A المقاطعة () من مؤشر ترابط آخر B يحدث قبل أن يكون مؤشر الترابط A يجد أن B قد انقطع بواسطة A (B يلقي استثناء أو اكتشاف B isInterredred () أو المقاطعة ()).
(7) نهاية مُنشئ الكائنات تحدث قبل ذلك وبداية المزروع النهائي للكائن
(8) إذا كان هناك إجراء ، فقد كان هناك عمل في العمل B ، و B-يحدث العمل قبل العمل ، ثم يحدث الإجراء قبل العمل C.
ما سبق هو كل شيء عن هذا المقال. سأقدمها لك هنا. آمل أن يكون من المفيد لك أن تتعلم وفهم المتغيرات المتقلبة في جافا.