من خلال تحليل المقالات الثلاثة السابقة ، لدينا فهم عميق للبنية الداخلية وبعض مفاهيم التصميم لـ Accountqueuedseuedsynchronizer ، ونحن نعلم أن الملخصات التي تحافظ على حالة التزامن واثنين من المناطق في طابور ، وهما طوابير متزامنة وقوائم الانتظار الشرطية على التوالي. دعنا نستخدم المراحيض العامة كتشبيه. قائمة انتظار المزامنة هي منطقة قائمة الانتظار الرئيسية. إذا لم تكن المراحيض العامة مفتوحة ، فيجب على كل من يريد الدخول إلى المرحاض قائمة الانتظار هنا. يتم تعيين قائمة انتظار الحالة بشكل رئيسي لانتظار الحالة. دعونا نتخيل أنه إذا حصل شخص ما على القفل أخيرًا ويدخل المرحاض من خلال قائمة الانتظار ، لكنه يجد أنه لا يجلب ورق التواليت قبل الراحة. على الرغم من أنه لا حول له ولا قوة عند مواجهة هذا الموقف ، إلا أنه يجب أن يقبل هذه الحقيقة أيضًا. في هذا الوقت ، يجب أن تخرج وإعداد ورق التواليت أولاً (أدخل قائمة انتظار الحالة للانتظار). بالطبع ، قبل الخروج ، يجب إطلاق القفل حتى يتمكن الآخرون من الدخول. بعد إعداد ورق التواليت (يتم استيفاء الظروف) ، يتعين عليه العودة إلى قائمة الانتظار المتزامنة إلى قائمة الانتظار مرة أخرى. بالطبع ، لم يجلب جميع الأشخاص الذين يدخلون الغرفة ورق التواليت. قد تكون هناك أسباب أخرى يجب عليهم مقاطعة العملية ووضع قائمة انتظار في قائمة انتظار الحالة أولاً. لذلك ، يمكن أن يكون هناك قوائم انتظار متعددة ، ويتم تعيين قوائم قوائم حالة مختلفة وفقًا لظروف الانتظار المختلفة. قائمة انتظار الحالة هي قائمة مرتبطة في اتجاه واحد. تحدد واجهة الشرط جميع العمليات في قائمة انتظار الحالة. تنفذ فئة InctionObject داخل جهاز AccountQueuedSynchronizer واجهة الحالة. دعونا نلقي نظرة على العمليات التي يتم تعريفها بواسطة واجهة الشرط.
شرط الواجهة العامة {// في انتظار الاستجابة لمقاطع مؤشر الترابط الفراغ Await () يلقي InterruptedException ؛ // في انتظار عدم الاستجابة لمقاطع الخيط باطلة AWAITININTRUPRUPTRUPRUPTRUPTRUPTRUPTRUPTRUPTRUPTRUPRUPTRUPTRUPTRUPTRIEPS . . . // استيقظ إشارة الفراغ عقدة الرأس () في قائمة انتظار الحالة ؛ // استيقظ جميع العقد من قائمة انتظار حالة Queue SignalAll () ؛ }على الرغم من أن واجهة الحالة تحدد العديد من الطرق ، إلا أنها تنقسم إلى فئتين في المجموع. الطريقة التي تبدأ بالانتظار هي الطريقة التي يدخل فيها مؤشر ترابط قائمة انتظار الشرط وينتظر ، والطريقة التي تبدأ بالإشارة هي الطريقة التي "يستيقظ" مؤشر الترابط في قائمة انتظار الشرط. تجدر الإشارة هنا إلى أن استدعاء طريقة الإشارة قد يستيقظ أو لا تستيقظ على الخيط. عندما يتم استيقاظ الخيط يعتمد على الموقف ، كما سيتم مناقشته لاحقًا ، ولكن استدعاء طريقة الإشارة سوف ينقل الخيط بالتأكيد من قائمة الانتظار الشرطية إلى ذيل قائمة انتظار التزامن. من أجل راحة السرد ، لن نقلق بشأن ذلك في الوقت الحالي. سوف ندعو طريقة الإشارة إلى تشغيل سلسلة قوائم الانتظار الشرطية للاستيقاظ. يرجى ملاحظة أن هناك 5 أنواع من أساليب الانتظار ، وهي انتظار مقاطعة مؤشر ترابط الاستجابة ، وانتظار مؤشر ترابط عدم الاستجابة ، والوقت النسبي غير المسبق ، والوقت النسبي للوقت ، والوقت المطلق ؛ لا يوجد سوى نوعين من طرق الإشارة ، وهما تشغيل عملية إيقاظ رأس قائمة انتظار الحالة فقط وإيقاظ جميع العقد في قائمة انتظار الحالة. نفس النوع من الطرق هي نفسها في الأساس. نظرًا لقيود المساحة ، من المستحيل وليس من الضروري التحدث عن هذه الأساليب بعناية. نحتاج فقط إلى فهم طريقة تمثيلية واحدة ثم ننظر إلى طرق أخرى لفهمها. لذلك في هذه المقالة ، سأتحدث فقط عن طريقة الانتظار وطريقة الإشارة بالتفصيل. لن تتم مناقشة الطرق الأخرى بالتفصيل ، ولكن ستنشر التعليمات البرمجية المصدر للرجوع إليها.
1. انتظر استجابة لحالة مقاطعة الموضوع
. } // إضافة مؤشر الترابط الحالي إلى ذيل عقدة قائمة انتظار الشرط = addConditionWaiter () ؛ // إطلاق القفل الكامل قبل إدخال الشرط الانتظار int saveState = commonRelease (العقدة) ؛ int interruptmode = 0 ؛ . تم إلغاء العقدة الأمامية لقائمة انتظار التزامن // 2. قم بتعيين حالة العقدة الأمامية لقائمة انتظار المزامنة للإشارة فشلت // 3. يتم إيقاظ العقدة الحالية بعد إطلاق العقدة الأمامية القفل. // يتحقق الخيط الحالي على الفور ما إذا كان قد توقف. إذا كان الأمر كذلك ، فهذا يعني أن العقدة تلغي حالة الانتظار. في هذا الوقت ، يجب نقل العقدة من قائمة انتظار الشرط إذا ((InterruptMode = cophInterrupruprupruprupruprupwHileWaiting (Node))! = 0) {break ؛ }} // بعد أن يستيقظ مؤشر الترابط ، سيحصل على القفل في الوضع الحصري إذا (الحصول على (عقدة ، SAVEDSTATE) && interruptmode! = throw_ie) {interruptmode = reinterrupt ؛ } // هذه العملية بشكل أساسي لمنع مؤشرات الترابط من الانقطاع قبل الإشارة ، مما يؤدي إلى عدم انقطاع الاتصال عن قائمة انتظار الشرط إذا (node.nextwaiter! = null) {unlinkcancelledwaiters () ؛ }. }}عندما يستدعي مؤشر ترابط طريقة الانتظار ، سيتم لف مؤشر الترابط الحالي كعقدة عقدة ووضعها في ذيل قائمة انتظار الشرط. في طريقة AddConditionWaiter ، إذا تم العثور على عقدة نهاية قائمة انتظار الشرط ، سيتم استدعاء طريقة UnlinkCancelledWaiters لمسح جميع العقد الملغاة في قائمة انتظار الشرط. هذه الخطوة هي التحضير لإدخال العقد. بعد التأكد من أن حالة عقدة الذيل هي أيضًا شرط ، سيتم إنشاء عقدة جديدة للف الخيط الحالي ووضعها في ذيل قائمة انتظار الحالة. لاحظ أن هذه العملية تضيف فقط العقد إلى ذيل قائمة انتظار المزامنة دون تعليق المواضيع.
الخطوة 2: حرر القفل تمامًا
// relection full the lock final int commonRelease (node node) {failean failed = true ؛ حاول {// الحصول على حالة التزامن الحالية int savedState = getState () ؛ // استخدم حالة التزامن الحالية لإطلاق القفل إذا (الإصدار (SaveState)) {FAIL = false ؛ // إذا تم إصدار القفل بنجاح ، فستوفر SaveState ؛ } آخر {// إذا فشل القفل ، رمي استثناء وقت التشغيل رمي جديد inchleartitorstateException () ؛ }} أخيرًا {// تأكد من تعيين العقدة على حالة إلغاء إذا (فشل) {node.waitstatus = node.cancelled ؛ }}}بعد لف الخيط الحالي في عقدة وإضافته إلى ذيل قائمة انتظار الشرط ، يتم استدعاء طريقة الإصلاح بالكامل لإطلاق القفل. لاحظ أن الطريقة المسمى CommonRelease تستخدم لإطلاق القفل تمامًا ، لأن القفل يعيد إدخاله ، لذلك تحتاج إلى تحرير القفل قبل الانتظار المشروط ، وإلا فلن يتمكن الآخرون من الحصول على القفل. في حالة فشل القفل ، سيتم طرح استثناء وقت التشغيل. إذا تم إصدار القفل بنجاح ، فسوف يعود إلى حالة التزامن السابقة.
الخطوة 3: اجعل الظروف تنتظر
. هناك العديد من الحالات التي يستيقظ فيها الخيط: // 1. تم إلغاء العقدة الأمامية لقائمة انتظار التزامن // 2. قم بتعيين حالة العقدة الأمامية لقائمة انتظار المزامنة للإشارة فشلت // 3. يتم إيقاظ العقدة الحالية بعد إطلاق العقدة الأمامية القفل. locksupport.park (هذا) ؛ // يستيقظ الخيط الحالي على الفور للتحقق مما إذا كان قد توقف. إذا كان الأمر كذلك ، فهذا يعني أن العقدة تلغي حالة الانتظار. في هذا الوقت ، يجب نقل العقدة من قائمة انتظار الشرط إذا ((InterruptMode = cophInterrupruprupruprupruprupwHileWaiting (Node))! = 0) {break ؛ }} // تحقق من حالة انقطاع مؤشر الترابط عندما ينتظر الحالة الخاصة int int int checkIntrupruprupruprupruprupruprupruprupt (عقدة العقدة) {// أن طلب المقاطعة هو قبل عملية الإشارة: throw_ie // طلب المقاطعة بعد عملية الإشارة: إعادة استلام // لم يتم استلام طلب المقاطعة خلال هذه الفترة: (transferafterCancelledWait (Node)؟ THER_IE: إعادة الانقطاع): 0 ؛} // نقل العقدة التي تلغي الحالة الانتظار من قائمة انتظار الشرط إلى قائمة انتظار المزامنة النهائية المنطقية النهائية المنطقية 0)) {// بعد تعديل الحالة ناجحًا ، ضع العقدة في ذيل قائمة انتظار المزامنة enq (العقدة) ؛ العودة صحيح. } // يشير هذا إلى أن عملية CAS فشلت ، مما يشير إلى أن المقاطعة تحدث بعد طريقة الإشارة بينما (! isonsyncqueue (node)) {// إذا لم تنقل الطريقة الصينية العقدة إلى قائمة انتظار المزامنة ، انتظر thread.yield () ؛ } إرجاع خطأ ؛}بعد اكتمال العمليتين أعلاه ، ستدخل حلقة بينما. يمكنك أن ترى أن Leop First يستدعي locksupport.park (هذا) لتعليق الخيط ، بحيث يتم حظر الخيط هنا طوال الوقت. بعد استدعاء طريقة الإشارة ، ما عليك سوى نقل العقدة من قائمة الانتظار الشرطية إلى قائمة انتظار المزامنة. ما إذا كان سيتم إيقاظ الموضوع يعتمد على الموقف. إذا وجدت أنه تم إلغاء العقدة الأمامية في قائمة انتظار المزامنة عند نقل العقدة ، أو يتم تحديث حالة العقدة الأمامية للإشارة ، وسوف تستيقظ كلتا الحالتين على الفور. خلاف ذلك ، لن يتم إيقاظ الخيط الموجود بالفعل في قائمة انتظار المزامنة في نهاية طريقة الإشارة ، ولكنه سينتظر حتى تستيقظ العقدة الأمامية. بطبيعة الحال ، بالإضافة إلى استدعاء طريقة الإشارة للاستيقاظ ، يمكن للموضوع أيضًا أن يستجيب للمقاطعات. إذا تلقى مؤشر الترابط طلب المقاطعة هنا ، فسيستمر تنفيذه. يمكنك أن ترى أنه بعد استيقاظ الخيط ، سيتحقق على الفور ما إذا كان يتم إيقاظه عن طريق المقاطعة أو من خلال طريقة الإشارة. إذا تم إيقاظها عن طريق المقاطعة ، فسيقوم أيضًا بنقل هذه العقدة إلى قائمة انتظار المزامنة ، ولكن يتم تحقيقها من خلال استدعاء طريقة TransferAfterCancelledWait. بعد التنفيذ النهائي لهذه الخطوة ، سيتم إرجاع المقاطعة وسيتم قفز الحلقة.
الخطوة 4: يتم إزالة العملية بعد العقدة من قائمة انتظار الحالة
// بعد أن يستيقظ مؤشر الترابط ، سيحصل على القفل في الوضع الحصري إذا (الحصول على (Node ، SaveState) && interruptmode! = throw_ie) {interruptmode = reinterrupt ؛ UnlinkCancElledWaiters () ؛} // المقاطعة المعالجة التي تستجيب لوضع المقاطعة إذا (interruptmode! = 0) {reportInterRuprupruptAfterWait (interruptmode) ؛} // بعد إنهاء الشرط ، فإنه سيجعل المعالجة المقابلة intrupted repretruprupterwait (int interruptmode) تم إلقاؤه if (interruptMode == throw_ie) {رمي جديد interruptedException () ؛ // إذا كان وضع المقاطعة قد تم إعادة انقطاعه ، فسيقوم بتعليق نفسه} آخر إذا (interruptMode == reinterrupt) {selfinterrupt () ؛ }}عندما ينهي الخيط حلقة بينما ، فإن الشرط ينتظر ، فسوف يعود إلى قائمة انتظار المزامنة. سواء كان ذلك بسبب استدعاء طريقة الإشارة إلى الوراء أو بسبب انقطاع الخيط ، ستكون العقدة في نهاية المطاف في قائمة الانتظار المتزامنة. في هذا الوقت ، سيتم استدعاء الطريقة المكتسبة لإجراء تشغيل الأقفال في قائمة انتظار المزامنة. لقد ناقشنا بالفعل هذه الطريقة بالتفصيل في مقالة الوضع الحصري. بمعنى آخر ، بعد أن تخرج العقدة من قائمة انتظار الحالة ، يذهب بطاعة إلى مجموعة الأقفال في الوضع الحصري. بعد أن تحصل هذه العقدة على القفل مرة أخرى ، سوف يطلق على طريقة التقرير EnterrupruprupruptAfterWait للرد وفقًا لذلك بناءً على الموقف المقاطعة خلال هذه الفترة. في حالة حدوث المقاطعة قبل طريقة الإشارة ، يكون InterruptMode throw_ie ، وسيتم طرح استثناء بعد الحصول على القفل مرة أخرى ؛ في حالة حدوث المقاطعة بعد طريقة الإشارة ، يتم إعادة انقطاع مقاطع InterruptMode ، وسيتم مقاطعة مرة أخرى بعد الحصول على القفل مرة أخرى.
2. في انتظار عدم الاستجابة لمقاطعات الخيط
. // إطلاق كامل القفل وإرجاع حالة التزامن الحالية int saveState = commonRelease (العقدة) ؛ المنقطع المنطقي = خطأ ؛ // العقد تنتظر مشروطًا في حلقة بينما (! isonsyncqueue (node)) {// يتم تعليق جميع مؤشرات الترابط في قائمة انتظار الشرط هنا locksupport.park (هذا) ؛ . }} إذا (الحصول على العقدة ، SaveState) || مقاطع) {// الرد على جميع طلبات المقاطعة هنا ، إذا تم استيفاء أحد الشرطين التاليين ، فسيقوم بتعليق نفسه // 1. يتلقى مؤشر الترابط طلب المقاطعة أثناء انتظار الشرط // 2. يتلقى مؤشر الترابط طلب المقاطعة في طريقة الحصول على SelfInterrupt () ؛ }}3. اضبط حالة الوقت النسبية (لا تدور)
// قم بتعيين حالة التوقيت في انتظار (الوقت النسبي) ، ولا تقم بإجراء الدوران في انتظار المباراة النهائية الطويلة (Awaitnanos (Nanostimeout الطويلة) على interruptedException {// إذا تم مقاطعة الخيط ، يتم إلقاء استثناء إذا (thread.interredred ()) } // إضافة مؤشر الترابط الحالي إلى ذيل عقدة قائمة انتظار الشرط = addConditionWaiter () ؛ // إطلاق القفل الكامل قبل إدخال حالة انتظار int saveState = commonRelease (العقدة) ؛ long time = system.nanotime () ؛ int interruptmode = 0 ؛ بينما (! isonsyncqueue (Node)) {// ugn armaut ما إذا كانت المهلة قد تم استخدامها إذا (nanostimeout <= 0l) {// إذا تم الانتهاء من المهلة ، فأنت بحاجة إلى تنفيذ حالة الإلغاء عملية الانتظار transferCancelledWait (العقدة) ؛ استراحة؛ } // شنق الخيط الحالي لفترة زمنية ، قد يستيقظ الخيط خلال هذه الفترة ، أو قد يستيقظ من تلقاء نفسه على قفل. // تحقق من معلومات المقاطعة أولاً بعد أن يستيقظ مؤشر الترابط إذا ((interruptMode = cophInterruprupruprupTwHiLewAiting (Node))! = 0) {break ؛ } طويل الآن = system.nanotime () ؛ // وقت المهلة ناقص وقت انتظار الحالة nanostimeout - = الآن - في الوقت الأخير ؛ آخر مرة = الآن ؛ } // بعد أن يستيقظ مؤشر الترابط ، سيحصل على القفل في الوضع الحصري إذا (الحصول على (Node ، SaveState) && interruptmode! = throw_ie) {interruptmode = reinterrupt ؛ } // لأن طريقة transferafterCancelledWait لا تفرغ nextwaiter ، كل ما تحتاجه للتنظيف هنا إذا (node.nextWaiter! = null) {unlinkcancelledwaiters () ؛ }. }.4. اضبط حالة الوقت النسبية (تدور)
. } // الحصول على المللي ثانية من المهلة الطويلة nanostimeout = unit.tonanos (time) ؛ // في حالة انقطاع الموضوع ، يتم إلقاء استثناء إذا (thread.Interreded ()) {رمي جديد interruptedException () ؛ } // إضافة مؤشر الترابط الحالي إلى ذيل عقدة قائمة انتظار الشرط = addConditionWaiter () ؛ // إطلاق القفل الكامل قبل إدخال الشرط لانتظار int saveState = commonRelease (العقدة) ؛ // احصل على المللي ثانية من الوقت الحالي طويلًا في الوقت الحالي = system.nanotime () ؛ توقيت منطقي = خطأ ؛ int interruptmode = 0 ؛ بينما (! isonsyncqueue (node)) {// إذا تم توقيت المهلة ، فأنت بحاجة إلى إجراء عملية انتظار حالة الإلغاء إذا (nanostimeout <= 0l) {timedout = transferafterCancelledWait (العقدة) ؛ استراحة؛ } // إذا كان وقت المهلة أكبر من وقت الدوران ، فسيتم تعليق الخيط لفترة من الوقت إذا كان (nanostimeout> = spallfortimeOutThreshold) {locksupport.parknanos (هذا ، nanostimeout) ؛ } // بعد أن يستيقظ مؤشر الترابط ، يتحقق من معلومات المقاطعة أولاً إذا (interruptMode = cophInterrupruprupruptWhiLewAiting (Node))! = 0) {break ؛ } طويل الآن = system.nanotime () ؛ // وقت المهلة في كل مرة يقوم فيها بطرح وقت الحالة في انتظار NanoStimeOut - = الآن - آخر مرة ؛ آخر مرة = الآن ؛ } // بعد أن يستيقظ مؤشر الترابط ، سيحصل على القفل في الوضع الحصري إذا (الحصول على (Node ، SaveState) && interruptmode! = throw_ie) {interruptmode = reinterrupt ؛ } // نظرًا لأن طريقة transferafterCancelledWait لا تفرغ nextwaiter ، فكل ما تحتاجه للتنظيف هنا إذا (node.nextWaiter! = null) {unlinkcancelledwaiters () ؛ }. } // إرجاع ما إذا كان علامة المهلة يعود! timedout ؛}5. اضبط حالة الوقت المطلق
. } // الحصول على المللي ثانية من الوقت المطلق الامتناع عن العمل = الموعد النهائي. getTime () ؛ // في حالة انقطاع الموضوع ، يتم إلقاء استثناء إذا (thread.Interreded ()) {رمي جديد interruptedException () ؛ } // إضافة مؤشر الترابط الحالي إلى ذيل عقدة قائمة انتظار الشرط = addConditionWaiter () ؛ // إطلاق القفل الكامل قبل إدخال الشرط الانتظار int saveState = commonRelease (العقدة) ؛ توقيت منطقي = خطأ ؛ int interruptmode = 0 ؛ بينما (! isonsyncqueue (node)) {// If Timeout ، تحتاج إلى تنفيذ عملية انتظار حالة إلغاء إذا (system.currentTimeMillis ()> Ampstime) {timedout = transferafterCancelledWait (node) ؛ استراحة؛ } // شنق الخيط لفترة زمنية ، يمكن خلالها إيقاظ الخيط ، أو قد يكون الوقت قد حان للاستيقاظ من تلقاء أنفسهم قفلة. // تحقق من معلومات المقاطعة أولاً بعد أن يستيقظ مؤشر الترابط ((interruptMode = checkInterruprupruptWhiLewaIting (العقدة))! = 0) {break ؛ }} // بعد أن يستيقظ مؤشر الترابط ، سيحصل على القفل في الوضع الحصري إذا (الحصول على (عقدة ، SAVEDSTATE) && interruptmode! = throw_ie) {interruptmode = reinterrupt ؛ } // لأن طريقة transferafterCancelledWait لا تفرغ nextwaiter ، كل ما تحتاجه للتنظيف هنا إذا (node.nextWaiter! = null) {unlinkcancelledwaiters () ؛ }. } // إرجاع ما إذا كان علامة المهلة يعود! timedout ؛}6. استيقظ عقدة الرأس في قائمة الانتظار الشرطية
// استيقظ على العقدة التالية في قائمة انتظار الإشارة الفراغية النهائية للشرط () {// الحكم على ما إذا كان مؤشر الترابط الحالي يحمل القفل إذا (! iSheldexclusival ()) {رمي جديد غير intervalyitorStateException () ؛ } العقدة أولاً = firstwaiter ؛ // إذا كان هناك قائمة انتظار في قائمة انتظار الشرط إذا (أولاً! = null) {// استيقظ عقدة الرأس في قائمة انتظار الشرط (أولاً) ؛ }} // استيقظ عقدة الرأس في قائمة انتظار الشرط Dosignal (العقدة الأولى) {do {// 1. انقل مرجع FirstWaiter واحدًا تلو الآخر if ((firstwaiter = first.nextWaiter) == null) {lastWaiter = null ؛ } // 2. تفريغ مرجع عقدة الخلف لعقدة الرأس أولاً. nextWaiter = null ؛ // 3. نقل عقدة الرأس إلى قائمة انتظار المزامنة ، ومن الممكن إيقاظ الخيط بعد اكتمال النقل // 4. في حالة فشل عملية TransferForSignal ، استيقظ في العقدة التالية} بينما (! transferforsignal (أولاً) && (أولاً = FirstWaiter)! = null) ؛} // نقل العقدة المحددة من قائمة انتظار الحالة إلى Quipe to tyseanization النهائي المنطقي node.condition ، 0)) {// إذا فشلت العملية لتحديث الحالة ، فإن إرجاع FALSE مباشرة // قد تكون طريقة transferafterCancelledWait غيرت الحالة أولاً ، مما تسبب في فشل عملية CAS هذه. } // أضف هذه العقدة إلى ذيل عقدة قائمة انتظار التزامن p = enq (العقدة) ؛ int ws = p.waitstatus ؛ if (ws> 0 ||! compareandsetwaitstatus (p ، ws ، node.signal)) {// سيتم إيقاظ مؤشر الترابط الحالي عند حدوث الموقف التالي // 1. العقدة الأمامية في حالة إلغاء // 2. حالة التحديث إلى الأمام هي عملية الإشارة فشلت LockSupport.unpark (Node.Thread) ؛ } إرجاع صحيح ؛}يمكن ملاحظة أن النواة النهائية لطريقة الإشارة هو استدعاء طريقة النقل. في طريقة TransferForSIsnal ، استخدم أولاً عملية CAS لتعيين حالة العقدة من الحالة إلى 0 ، ثم اتصل بالطريقة ENQ لإضافة العقدة إلى ذيل قائمة انتظار المزامنة. نرى بيان الحكم التالي. يستخدم بيان الحكم هذا بشكل أساسي لتحديد موعد إيقاظ الموضوع. في حالة حدوث هاتين الحالتين ، سيتم إيقاظ الخيط على الفور. أحدهما عندما يتم اكتشاف أن حالة العقدة السابقة تم إلغاؤها ، والآخر هو عندما تفشل حالة العقدة السابقة في التحديث. ستستيقظ كلتا الحالتين على الفور في الخيط ، وإلا فإنه سيتم ببساطة نقل العقدة من قائمة الانتظار الشرطية إلى قائمة انتظار المزامنة ، ولن تستيقظ على الفور الخيط في العقدة. تتشابه طريقة Signalall تقريبًا ، باستثناء أنه يحلق من خلال جميع العقد في قائمة الانتظار الشرطية وتنقلها إلى قائمة الانتظار المتزامنة. لا تزال طريقة نقل العقد تستدعي طريقة النقل.
7. استيقظ جميع العقد من قائمة انتظار الحالة
// استيقظ جميع العقد خلف قائمة الانتظار في قائمة انتظار الإشارة الفراغية النهائية () {// الحكم على ما إذا كان الخيط الحالي يحمل القفل إذا (! iSheldexclusival ()) {رمي جديد غير unalfalMonitorStateException () ؛ } // الحصول على عقدة رأس قائمة انتظار الشرط أولاً = firstwaiter ؛ if (أولاً! = null) {// استيقظ جميع العقد من قائمة انتظار الحالة dosignalall (أولاً) ؛ }} // استيقظ جميع العقد في قائمة انتظار الشرط الخاصة dosignalall (العقدة الأولى) {// أولاً فارغة مراجع عقدة الرأس وعقدة الذيل lastWaiter = firstwaiter = null ؛ do {// احصل على مرجع العقدة الخلف أولاً = first.nextWaiter ؛ // تفريغ المرجع اللاحق للعقدة المراد نقلها أولاً. nextWaiter = null ؛ // نقل العقدة من قائمة الانتظار الشرطية إلى نقل قائمة انتظار المزامنة (الأول) ؛ // نقطة الإشارة إلى العقدة التالية أولاً = التالي ؛ } بينما (الأول! = فارغ) ؛}في هذه المرحلة ، انتهى تحليل رمز مصدر المصدر التجريدي بالكامل. أعتقد أنه من خلال هذه التحليلات الأربعة ، يمكن للجميع إتقان وفهم AQS. هذه الفئة مهمة للغاية بالفعل لأنها حجر الزاوية في العديد من فئات التزامن الأخرى. نظرًا للمستوى المحدود وقدرة التعبير للمؤلف ، إذا لم تكن هناك بيانات واضحة أو فهم غير كافٍ ، فيرجى تصحيحها في الوقت المناسب والمناقشة والتعلم معًا. يمكنك ترك رسالة لقراءة المشكلة أدناه. إذا كنت بحاجة إلى رمز مصدر تعليق AQS ، فيمكنك أيضًا الاتصال بالمؤلف لطلبه.
ملاحظة: يعتمد جميع التحليلات المذكورة أعلاه على JDK1.7 ، وستكون هناك اختلافات بين الإصدارات المختلفة ، يحتاج القراء إلى الانتباه.
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.