أتذكر عندما بدأت في تعلم Java لأول مرة ، تمت مواجهة المزامنة عندما واجهت موقفًا متعدد الخيوط. بالمقارنة معنا في ذلك الوقت ، كان المزامنة سحرية وقوية للغاية. في ذلك الوقت ، قدمناها اسم "المزامنة" ، والتي أصبحت أيضًا دواءًا جيدًا بالنسبة لنا لحل المواقف المتعددة. ولكن كما نتعلم ، نعلم أن المزامنة هي قفل الوزن الثقيل ، وبالنسبة للقفل ، سيبدو ضخمًا لدرجة أننا نعتقد أنه ليس فعالًا ويتخلى عنه ببطء.
من المسلم به ، مع التحسينات المختلفة التي أجراها Javas SE 1.6 على متزامن ، لا يبدو أن المزامنة ثقيلة. أدناه ، اتبع LZ لاستكشاف آلية تنفيذ متزامنة ، كيف تعمل Java على تحسينه ، وآلية تحسين القفل ، وهيكل تخزين القفل وعملية الترقية ؛
مبدأ التنفيذ
يمكن أن يضمن Synchronized أن يتم تشغيل الطريقة أو كتلة التعليمات البرمجية ، ويمكن أن تدخل طريقة واحدة فقط في المنطقة الحرجة في نفس الوقت. في الوقت نفسه ، يمكن أن يضمن أيضًا رؤية ذاكرة المتغيرات المشتركة.
يمكن استخدام كل كائن في Java كقفل ، وهو أساس المزامنة لتنفيذ المزامنة:
طريقة المزامنة الشائعة ، القفل هو طريقة التزامن الثابت لكائن مثيل الحالي ، القفل هو كتلة تزامن كائن الفئة الحالية ، القفل هو الكائن بين قوسين عندما يصل مؤشر ترابط إلى كتلة رمز التزامن ، يحتاج أولاً إلى الحصول على القفل لتنفيذ رمز التزامن. عند خروج أو إلقاء استثناء ، يجب إطلاق القفل. فكيف تنفذ هذه الآلية؟ دعونا نلقي نظرة أولاً على رمز بسيط:
الفئة العامة SynchronizedTest {public synchronized void test1 () {} public void test2 () {synchronized (this) {}}}استخدم أداة Javap لعرض معلومات ملف الفئة التي تم إنشاؤها لتحليل تنفيذ مزامنة
كما يتضح من ما ورد أعلاه ، يتم تنفيذ كتلة رمز التزامن باستخدام تعليمات Monitorenter و Monitorexit. تعتمد طريقة التزامن (لا تظهر أنك تحتاج إلى النظر في تطبيق JVM الأساسي) على تطبيق ACC_Synchronized على معدّل الطريقة.
كتلة التعليمات البرمجية المتزامنة: يتم إدراج تعليمات المراقبة في موضع بدء كتلة رمز التزامن ، ويتم إدراج تعليمات monitorexit في الموضع النهائي لكلية رمز التزامن. يحتاج JVM إلى التأكد من أن كل مراقب لديه monitorexit يتوافق معها. أي كائن لديه شاشة مرتبطة به ، وعندما يتم الاحتفاظ بالمراقبة ، سيتم قفله. عندما ينفذ مؤشر ترابط تعليمات المراقبة ، سيحاول الحصول على ملكية الشاشة المقابلة للكائن ، أي محاولة الحصول على قفل الكائن ؛
الطريقة المتزامنة: سيتم ترجمة الطريقة المتزامنة إلى مكالمات الطريقة العادية وتعليمات الإرجاع مثل: تعليمات invokevirtual و areturn. لا توجد تعليمات خاصة على مستوى VM Bytecode لتنفيذ الطريقة المعدلة المتزامنة. بدلاً من ذلك ، يتم وضع موضع العلامة المتزامن 1 في حقل Access_Flags للطريقة في جدول الطريقة في ملف الفئة ، مما يشير إلى أن الطريقة هي طريقة متزامنة وتستخدم الكائن الذي يستدعي الطريقة أو الفئة التي تنتمي إلى الطريقة لتمثيل KLASS ككائن قفل (الرجوع إلى: http://www.vevb.com/Article/129245.htm)
دعنا نستمر في تحليله ، ولكن قبل أن نتعمق أكثر ، نحتاج إلى فهم مفهومين مهمين: رأس جافا كائن وراقب.
رأس جافا كائن ، شاشة
رؤوس وشاشات كائن Java هي الأساس لتنفيذ متزامن! فيما يلي مقدمة مفصلة لهذين المفهومين.
رأس جافا كائن
يقع القفل المستخدم للمزامنة في رأس كائن Java ، فما هو رأس كائن Java؟ يتضمن رأس كائن الجهاز الظاهري للنقطة الساخنة جزأين من البيانات: علامة Mark (Mark Field) ومؤشر Klass (Type Pointer). Klass Point هو مؤشر لبيانات تعريف فئة الكائن. يستخدم الجهاز الظاهري هذا المؤشر لتحديد مثيل الفئة الذي هو الكائن. يتم استخدام Mark Word لتخزين بيانات وقت التشغيل الخاصة بالكائن. هذا هو المفتاح لتنفيذ الأقفال الخفيفة الوزن والأقفال المتحيزة ، وبالتالي فإن ما يلي سيركز عليه.
مارك كلمة.
يتم استخدام Mark Word لتخزين بيانات وقت التشغيل للكائن نفسه ، مثل رمز التجزئة (HashCode) ، و GC Generation Age ، وعلم حالة القفل ، والأقفال التي يحتفظ بها مؤشرات الترابط ، ومعرف الخيط المتحيز ، والطابع الزمني المتحيز ، إلخ. يمكن لـ JVM Virtual Machine تحديد حجم كائن Java من خلال معلومات البيانات الوصفية لكائن Java ، ولكن لا يمكن تأكيد حجم الصفيف من بيانات التعريف الخاصة بالمصفوفة ، لذلك يتم استخدام قطعة لتسجيل طول الصفيف. الشكل التالي هو بنية التخزين لرأس كائن Java (الجهاز الظاهري 32 بت):
معلومات رأس الكائن هي تكلفة تخزين إضافية مستقلة عن البيانات المحددة بواسطة الكائن نفسه. ومع ذلك ، بالنظر إلى الكفاءة المكانية للجهاز الظاهري ، تم تصميم Mark Word كهيكل بيانات غير مثبت لتخزين أكبر قدر ممكن من البيانات في ذاكرة مساحة صغيرة جدًا. ستعيد استخدام مساحة التخزين الخاصة بها وفقًا لحالة الكائن. بمعنى أن Mark Word ستتغير مع تشغيل البرنامج ، وحالة التغيير هي كما يلي (الجهاز الظاهري 32 بت):
مقدمة موجزة لرؤوس جافا كائن ، دعونا نلقي نظرة على الشاشة.
شاشة
ما هو الشاشة؟ يمكننا أن نفهمها كأداة تزامن أو آلية التزامن ، والتي عادة ما يتم وصفها ككائن.
تمامًا مثل كل شيء هو كائن ، فإن جميع كائنات Java هي شاشات طبيعية ، وكل كائن Java لديه القدرة على أن يصبح شاشة ، لأنه في تصميم Java ، يحمل كل كائن Java قفلًا غير مرئي لأنه يخرج من الرحم. يطلق عليه قفل أو قفل مراقبة داخلي.
الشاشة هي بنية بيانات مملوكة ملكية خاصة. يحتوي كل موضوع على قائمة بسجلات الشاشة المتاحة وقائمة عالمية متاحة. سيتم ربط كل كائن مغلق بشاشة (Lockword في علامة Markword من رأس الكائن يشير إلى عنوان بدء الشاشة). في الوقت نفسه ، يوجد حقل مالك في الشاشة يخزن المعرف الفريد للخيط الذي يمتلك القفل ، مما يشير إلى أن القفل يشغله الخيط. هيكلها على النحو التالي:
المالك: NULL في البداية يعني أنه لا يوجد مؤشر ترابط حاليًا يمتلك MonitorRecord. عندما يمتلك الخيط بنجاح القفل ، فإنه يحفظ الهوية الفريدة للموضوع ، وعندما يتم إصدار القفل ، يتم ضبطه على NULL ؛
EntryQ: قم بربط Mutex (Semaphore) لحظر جميع المواضيع التي تحاول قفل MonitorRecord.
rcthis: يمثل عدد جميع المواضيع المحظورة أو تنتظر على monitorrecord.
العش: تستخدم لتنفيذ عد أقفال إعادة الدخول.
HashCode: يحفظ قيمة Hashcode المنسوخة من رأس الكائن (قد يحتوي أيضًا على GCAGE).
المرشح: يستخدم لتجنب الحظر غير الضروري أو في انتظار أن تستيقظ المواضيع ، لأن موضوع واحد فقط يمكنه امتلاك القفل بنجاح في كل مرة. إذا كان الخيط السابق الذي يطلق القفل يستيقظ كل خيوط الحظر أو الانتظار في كل مرة ، فسيؤدي ذلك إلى تبديل السياق غير الضروري (من الحظر إلى الاستعداد ثم الحظر مرة أخرى بسبب فشل قفل المنافسة) وبالتالي يؤدي إلى تدهور الأداء الشديد. يحتوي المرشح على قيمتان محتملين فقط: 0 يعني أنه لا يوجد موضوع يحتاج إلى إيقاظ ما يصل إلى 1 وسائل لإيقاظ موضوع خليفة للتنافس على القفل.
المرجع: تحدث عن متزامن في تزامن جافا
نحن نعلم أن المزامنة هي قفل الوزن الثقيل وكفاءته ليست جيدة جدًا. في الوقت نفسه ، كان هذا المفهوم دائمًا في أذهاننا. ومع ذلك ، فقد تم تحسين تنفيذ التزامن في JDK1.6 ، مما يجعله غير ثقيل. إذن ما هي طرق التحسين التي تستخدمها JVM؟
قفل التحسين
يقدم JDK1.6 الكثير من التحسينات لتنفيذ الأقفال ، مثل أقفال الدوران ، وأقفال الدوران التكيفية ، والتخلص من القفل ، والخشونة ، وأقفال التحيز ، وأقفال خفيفة الوزن وغيرها من التقنيات لتقليل النفقات العامة لعملية القفل.
هناك أربع حالات رئيسية من الأقفال ، وهي: حالة قفل خالية من القفل ، حالة القفل المتحيزة ، حالة قفل خفيفة الوزن ، ودولة قفل الوزن الثقيل. سوف ترقية تدريجيا مع المنافسة الشرسة. لاحظ أنه يمكن ترقية الأقفال ولا يمكن تخفيضها. هذه الاستراتيجية هي تحسين كفاءة الحصول على الأقفال وإصدارها.
قفل تدور
يتطلب حظر الخيط والاستيقاظ أن يتغير وحدة المعالجة المركزية من حالة المستخدم إلى الحالة الأساسية. يعد الحجب والاستيقاظ بشكل متكرر مهمة ثقيلة لوحدة المعالجة المركزية ، وسوف يضع حتماً الكثير من الضغط على الأداء المتزامن للنظام. في الوقت نفسه ، وجدنا أنه في العديد من التطبيقات ، ستستمر حالة قفل قفل الكائن لفترة قصيرة جدًا فقط. من غير الجدير بمنع حظر وتستيقظ الخيط في هذه الفترة القصيرة جدًا من الزمن. لذلك يتم تقديم قفل الدوران.
ما هو قفل الدوران؟
ما يسمى قفل الدوران هو السماح للموضوع بانتظار فترة من الوقت وعدم تعليقه على الفور لمعرفة ما إذا كان الخيط الذي يحمل القفل سيصدر القفل بسرعة. كيف تنتظر؟ مجرد أداء دورة لا معنى لها (تدور).
لا يمكن أن يحل انتظار Spin Waiting ، دعنا نتحدث عن متطلبات عدد المعالجات (متعددة النواة ، ويبدو أنه لا يوجد معالج واحد الآن). على الرغم من أنه يمكن أن يتجنب النفقات العامة الناتجة عن تبديل الخيط ، إلا أنه يستغرق وقت المعالج. إذا كان الخيط الذي يحمل القفل يطلق القفل بسرعة ، فستكون كفاءة الدوران جيدة جدًا. على العكس من ذلك ، سوف يستهلك موضوع الدوران موارد المعالجة دون جدوى. لن يقوم بأي عمل ذي معنى. إنها عادة ما تحتل الحفرة ولا تقل ، الأمر الذي سيؤدي بدلاً من ذلك إلى هدر الأداء. لذلك ، يجب أن يكون للوقت لانتظار الدوران (عدد الدورات) حد. إذا تجاوز الدوران الوقت المحدد ولم يحصل على القفل ، فيجب تعليقه.
يتم تقديم Spinlock في JDK1.4.2 ويتم إيقاف تشغيله افتراضيًا ، ولكن يمكن تشغيله باستخدام -xx:+USESPINNING ، ويتم تشغيله افتراضيًا في JDK1.6. العدد الافتراضي للدوران في نفس الوقت هو 10 مرات ، والتي يمكن تعديلها بواسطة المعلمة -xx: preblockspin ؛
إذا قمت بضبط عدد الدوران من قفل الدوران من خلال المعلمة -xx: preblockspin ، فسوف يسبب الكثير من الإزعاج. إذا قمت بضبط المعلمة إلى 10 ، ولكن العديد من مؤشرات الترابط في النظام تطلق القفل عندما تخرج فقط (إذا قمت بتدوير مرة أو مرتين ، يمكنك الحصول على القفل) ، هل ستشعر بالحرج؟ لذلك ، قدمت JDK1.6 أقفال تدور تكيفية ، مما يجعل الأجهزة الافتراضية أكثر ذكاءً وأكثر ذكاءً.
تكييف قفل الدوران
JDK1.6 يقدم قفل تدور أكثر ذكاء ، وهو قفل تدور التكيفي. يعني التكيف المزعوم أن عدد الدورات لم يعد ثابتًا ، ويتم تحديده في وقت الدوران على نفس القفل وحالة مالك القفل. كيف تفعل ذلك؟ إذا كان الخيط يدور بنجاح ، فسيكون عدد الدورات في المرة القادمة ، لأن الجهاز الظاهري يعتقد أنه منذ آخر مرة نجحت فيها ، من المحتمل أن يكون الدوران ناجحًا مرة أخرى ، وسيسمح للدوران بالانتظار لمزيد من المرات. على العكس من ذلك ، إذا كان يمكن أن يكون عدد قليل من الدورات ناجحة في قفل معين ، فسيتم تقليل عدد الدورات أو حتى حذفها عندما يكون القفل مطلوبًا في المستقبل ، حتى لا يضيع موارد المعالج.
من خلال أقفال الدوران التكيفي ، مع استمرار تحسين تشغيل تشغيل البرنامج ومراقبة الأداء ، سيصبح التنبؤ الخاص بالجهاز الظاهري لحالة قفل البرنامج أكثر وأكثر دقة ، وستصبح الأجهزة الافتراضية أكثر ذكاءً.
القفل القضاء
من أجل ضمان سلامة البيانات ، نحتاج إلى مزامنة هذا الجزء من العملية عند إجراء العمليات ، ولكن في بعض الحالات ، يكتشف JVM أنه لا توجد إمكانية للمنافسة المشتركة للبيانات ، وهذا هو السبب في أن JVM ستقفل أقفال المزامنة هذه. أساس التخلص من القفل هو دعم البيانات لتحليل الهروب.
إذا لم تكن هناك منافسة ، فلماذا لا تزال بحاجة إلى إضافة قفل؟ لذلك يمكن أن يؤدي التخلص من القفل إلى توفير وقت لا معنى له لطلب الأقفال. ما إذا كان المتغير ضروريًا للأجهزة الظاهرية لتحديد ما إذا كان يتم استخدام تحليل تدفق البيانات ، ولكن هل لا يزال من غير الواضح المبرمجين الأمريكيين؟ هل سنضيف المزامنة قبل كتلة الكود التي تعرف بوضوح أنه لا توجد منافسة بيانات؟ لكن في بعض الأحيان ليس البرنامج ما نفكر فيه؟ على الرغم من أننا لا نعرض القفل ، عندما نستخدم بعض واجهات برمجة التطبيقات المدمجة في JDK ، مثل StringBuffer ، Vector ، Hashtable ، وما إلى ذلك ، ستكون هناك عملية قفل غير مرئية في هذا الوقت. على سبيل المثال ، طريقة Adpend () StringBuffer وطريقة ADD () المتجه:
public void vectortest () {vector <string> vector = new vector <string> () ؛ لـ (int i = 0 ؛ i <10 ؛ i ++) {vector.add (i+"") ؛ } system.out.println (متجه) ؛ }عند تشغيل هذا الرمز ، يمكن لـ JVM اكتشاف أن المتجه المتغير لا يهرب من الطريقة Vectortest () ، بحيث يمكن لـ JVM التخلص من عملية القفل بجرأة داخل المتجه.
قفل خشن
نحن نعلم أنه عند استخدام قفل المزامنة ، يجب أن يكون نطاق كتلة التزامن صغيرًا قدر الإمكان - يزامن فقط في النطاق الفعلي للبيانات المشتركة. والغرض من ذلك هو تقليل عدد العمليات التي تحتاج إلى مزامنة قدر الإمكان. إذا كانت هناك منافسة قفل ، يمكن أن يحصل الخيط الذي ينتظر القفل أيضًا على القفل في أقرب وقت ممكن.
في معظم الحالات ، يكون العرض أعلاه صحيحًا ، وقد التزمت LZ دائمًا بهذا الرأي. ومع ذلك ، إذا كانت سلسلة من عمليات القفل وإلغاء القفل المستمر قد تؤدي إلى خسائر غير ضرورية في الأداء ، فسيتم تقديم مفهوم قفل Slutty.
من الأسهل فهم مفهوم القفل ، وهو توصيل عمليات القفل وإلغاء القفل المتعددة معًا والتوسع في قفل بمدى أكبر. كما هو موضح في المثال أعلاه: يحتاج المتجه إلى إضافة عملية قفل في كل مرة يضيف فيها. يكتشف JVM أن نفس الكائن (المتجه) مقفل ومقره بشكل مستمر ، وسوف يندمج مجموعة أكبر من العمليات المقفلة والمفصلة ، أي أن العملية المقفلة والمفتحة سيتم نقلها خارج الحلقة.
قفل خفيف الوزن
الغرض الرئيسي من إدخال أقفال خفيفة الوزن هو تقليل استهلاك الأداء الناجم عن استخدام Mutexhes لنظام التشغيل تحت فرضية مسابقات متعددة بدون مؤشرات ترابط متعددة. عند إيقاف تشغيل وظيفة قفل التحيز أو تتنافس عدة مؤشرات ترابط على أقفال التحيز ، سيتم ترقية قفل التحيز إلى قفل خفيف الوزن ، ثم سيتم محاولة القفل الخفيف ، والخطوات كما يلي:
احصل على القفل
حدد ما إذا كان الكائن الحالي في حالة خالية من القفل (HashCode ، 0 ، 01). إذا كان الأمر كذلك ، فسيقوم JVM أولاً بإنشاء مساحة تسمى Lock Record في إطار المكدس من مؤشر الترابط الحالي لتخزين نسخة Mark Word الحالية من كائن القفل (يضيف المسؤول بادئة نازحة إلى هذه النسخة ، وهي كلمة Mark Word) ؛ خلاف ذلك ، تنفيذ الخطوة (3) ؛
يستخدم JVM عملية CAS لمحاولة تحديث كلمة علامة الكائن إلى تصحيح يشير إلى السجل. إذا كان ذلك يشير بنجاح إلى أن القفل قد تم التنافس عليه ، فسيتم تغيير علامة القفل إلى 00 (مما يشير إلى أن الكائن في حالة قفل خفيفة الوزن) ، ويؤدي عملية التزامن ؛ إذا فشلت ، قم بإجراء الخطوة (3) ؛
حدد ما إذا كانت كلمة علامة الكائن الحالي تشير إلى إطار المكدس للمعلومات الحالية. إذا كان الأمر كذلك ، فهذا يعني أن مؤشر الترابط الحالي يحمل بالفعل قفل الكائن الحالي ، ثم ينفذ مباشرة كتلة الكود المتزامن ؛ خلاف ذلك ، يمكن أن يعني فقط أن كائن القفل قد تم الاستيلاء عليه بواسطة مؤشرات ترابط أخرى. في هذا الوقت ، يجب توسيع قفل الوزن الخفيف إلى قفل ثقيل ، ويصبح جزء العلم القفل 10 ، وسيقوم الخيط الذي ينتظر لاحقًا بإدخال حالة الحظر ؛
حرر القفل
يتم إصدار أقفال الوزن الخفيفة أيضًا من خلال عمليات CAS ، والخطوات الرئيسية هي كما يلي:
قم بإزالة البيانات المحفوظة في كلمة Mark Mark النازحة في قفل الاستحواذ الخفيف ؛
استبدل البيانات التي تم استردادها في Mark Word مع عملية CAS. إذا نجحت ، فهذا يعني أن القفل قد تم إصداره بنجاح ، وإلا فإنه سيتم تنفيذه (3) ؛
إذا فشل استبدال عملية CAS ، فهذا يعني أن الخيوط الأخرى تحاول الحصول على القفل ، ويجب إيقاظ الخيط المعلق أثناء إطلاق القفل.
بالنسبة للأقفال الخفيفة ، فإن الأساس لتحسين الأداء هو أنه "بالنسبة لمعظم الأقفال ، لن تكون هناك منافسة طوال دورة الحياة بأكملها". إذا تم كسر هذا الأساس ، بالإضافة إلى النفقات العامة الحصرية المتبادلة ، فهناك عمليات CAS إضافية. لذلك ، في حالة المنافسة متعددة الخيوط ، تكون الأقفال الخفيفة أبطأ من أقفال الوزن الثقيل ؛
يوضح الشكل التالي عملية الاستحواذ والإفراج عن أقفال خفيفة الوزن
قفل إيجابي
الغرض الرئيسي من إدخال الأقفال المتحيزة هو تقليل مسارات تنفيذ قفل الخفيفة غير الضرورية دون منافسة متعددة الخيوط. ذكر أعلاه أن تشغيل القفل وإلغاء قفل الأقفال الخفيفة يتطلب الاعتماد على تعليمات ذرية متعددة CAS. فكيف يقلل قفل التحيز عمليات CAS غير الضرورية؟ يمكننا أن نرى هيكل العلامة العمل. تحتاج فقط إلى التحقق مما إذا كان قفلًا متحيزًا ، يتم تحديد القفل على أنه و ThreadId. تدفق المعالجة كما يلي:
احصل على القفل
اكتشف ما إذا كانت علامة Mark في حالة قابلة للتحيز ، أي ما إذا كان قفلًا متحيزًا 1 ، ولف تحديد القفل هو 01 ؛
إذا كانت حالة قابلة للتحيز ، فاختبر ما إذا كان معرف مؤشر الترابط هو معرف مؤشر الترابط الحالي. إذا كان الأمر كذلك ، قم بتنفيذ الخطوة (5) ، وإلا قم بتنفيذ الخطوة (3) ؛
إذا لم يكن معرف الخيط هو معرف مؤشر الترابط الحالي ، فسيتم تنافس القفل بواسطة CAS. إذا نجحت المنافسة ، يتم استبدال معرف مؤشر ترابط Mark Word بمعرف مؤشر الترابط الحالي ، وإلا فإن مؤشر الترابط (4) ؛
فشل قفل مسابقة CAS ، والذي يثبت أن هناك حاليًا وضع مسابقة متعدد الخيوط. عند الوصول إلى نقطة الأمان العالمية ، يتم تعليق الخيط الذي يحصل على القفل المتحيز ، ويتم ترقية القفل المتحيز إلى قفل خفيف الوزن ، ثم يستمر مؤشر الترابط المحظور عند نقطة الأمان في تنفيذ كتلة الكود المتزامن ؛
تنفيذ كتل التعليمات البرمجية المتزامنة
إطلاق الأقفال. يتبنى إصدار القفل المتحيز آلية لا يمكن للمنافسة فيها سوى إطلاق القفل. لن يطلق الخيط بنشاط القفل المتحيز ويحتاج إلى انتظار تنافس مؤشرات الترابط الأخرى. يتطلب التراجع عن الأقفال المتحيزة في انتظار نقطة أمان عالمية (هذه النقطة هي أنه لا يوجد رمز يتم تنفيذه في). الخطوات كما يلي:
توقف عن الخيط مع قفل متحيز وتحديد ما إذا كان حجر كائن القفل لا يزال في الحالة المقفلة ؛
فتح التحيز تجاه SU واستعادة إلى حالة قفل (01) أو حالة قفل خفيفة الوزن ؛
يوضح الشكل التالي عملية الاستحواذ والإفراج عن الأقفال المتحيزة
قفل الوزن الثقيل
يسمى قفل الوزن أيضًا مراقبة الكائن (الشاشة) في JVM. يشبه إلى حد كبير Mutex في C. بالإضافة إلى وظيفة Mutex (0 | 1) الحصرية بشكل متبادل ، وهي مسؤولة أيضًا عن تنفيذ وظيفة Semaphore ، أي أنه يحتوي على قائمة انتظار على الأقل من أقفال المنافسة وقائمة انتظار حظر الإشارة (قائمة انتظار الانتظار). السابق مسؤول عن الاستبعاد المتبادل ، ويستخدم الأخير لمزامنة الخيط.
يتم تنفيذ أقفال الوزن الثقيل من خلال شاشات (شاشات) داخل الكائنات ، حيث يكون جوهر الشاشات هو الاعتماد على تنفيذ قفل Mutex لنظام التشغيل الأساسي. يتطلب التبديل بين مؤشرات الترابط لنظام التشغيل التبديل من حالة المستخدم إلى حالة kernel ، وتكلفة التبديل مرتفعة للغاية.
لخص
ما سبق هو كل محتوى هذه المقالة حول التفسير التفصيلي لمبدأ التنفيذ المتماسك في Java. آمل أن يكون ذلك مفيدًا للجميع. إذا كانت هناك أي أوجه قصور ، فيرجى ترك رسالة لإشارةها. شكرا لك يا أصدقائك لدعمكم لهذا الموقع!