عندما يغير كائن حالة الوصول إليه ، يمكن وضع إشارة إلى الكائن في قائمة انتظار مرجعية. يتم استخدام قوائم الانتظار هذه من قبل جامع القمامة للتواصل مع الكود لدينا حول التغييرات في إمكانية الوصول إلى الكائن. تعتبر قوائم الانتظار هذه هي أفضل طريقة للكشف عن تغييرات إمكانية الوصول ، على الرغم من أنه يمكننا أيضًا اكتشاف تغييرات إمكانية الوصول للكائن عن طريق التحقق مما إذا كانت قيمة إرجاع طريقة GET خالية.
يمكن أن ترتبط الكائنات المرجعية بقوائم محددة عند بنائها. يوفر كل فئة فرعية من المرجع منشئات من النموذج التالي:
. مرجع القوة العامة (مرجع T ، مرجعية): تنشئ هذه الطريقة كائن مرجعي جديد مع كائن مرجعي معين ويسجل كائن المرجع إلى قائمة الانتظار المحددة. يتم إدراج المراجع الضعيفة والمراجع الناعمة في قائمة الانتظار بعد أن تحدد جامع القمامة أن كائناتها المرجعية تدخل حالة الوصول المحددة التي تمثلها ، ويتم مسح كلا المرجعين قبل قائمة انتظار الإدراج. سيتم أيضًا إدراج المراجع الافتراضية في قائمة الانتظار بعد أن تحدد جامع القمامة أن كائناته المرجعية قد دخلت الحالة الافتراضية التي يمكن الوصول إليها ، لكن لن يتم مسحها. بمجرد إدراج الكائن المرجعي في قائمة الانتظار بواسطة جامع القمامة ، ستكون قيمة إرجاع طريقة GET خالية بالتأكيد ، لذلك لا يمكن إحياء الكائن أبدًا.
لا يقوم تسجيل كائن مرجعي في قائمة انتظار مرجعية بإنشاء مرجع بين قائمة الانتظار والكائن المرجعي. إذا أصبح كائننا المرجعي نفسه غير قابل للوصول ، فلا يمكن إدراجه في قائمة الانتظار. لذلك ، يحتاج تطبيقنا إلى الحفاظ على إشارة قوية إلى جميع الكائنات المشار إليها.
يوفر فئة ReferenceQueue ثلاث طرق لإزالة المراجع في قائمة الانتظار:
تتيح طريقة الاستطلاع للمعلومات للاستعلام عما إذا كانت المرجع في قائمة انتظار وتنفيذ إجراء محدد عند وجود المرجع في قائمة الانتظار. يمكن أن تتعامل طريقة إزالة المواقف الأكثر تعقيدًا (الأقل شيوعًا) ، حيث يكون مؤشر ترابط مخصص مسؤولاً عن إزالة المراجع من قائمة الانتظار وإجراء الإجراءات المناسبة. سلوك الحظر لهذه الأساليب هو نفسه سلوك الحظر المحدد في الكائن. للحصول على مرجع محدد ، يمكننا الاستعلام عما إذا كان في قائمة الانتظار بواسطة طريقة isenqueued ، أو إجبارها على قائمة الانتظار عن طريق استدعاء طريقة enqueue ، ولكن عادةً ما يتم هذا النوع من التوصيل بواسطة جامع القمامة.
يمكن استخدام المراجع الافتراضية في قائمة الانتظار المرجعية لتحديد متى يمكن إعادة تدوير كائن. لا يمكننا الوصول إلى أي كائن من خلال المراجع الافتراضية ، حتى إذا كان الكائن يمكن الوصول إليه بطرق أخرى ، لأن طريقة الحصول على المرجع الظاهري تُرجع دائمًا. في الواقع ، فإن استخدام المراجع الافتراضية للعثور على الكائن المراد إعادة تدويره هو الطريقة الأكثر أمانًا ، لأنه سيتم إدراج المراجع الضعيفة والمراجع الناعمة في قائمة الانتظار بعد أن يتم إنهاء الكائن ، بينما يتم إدراج المراجع الافتراضية في قائمة الانتظار بعد إنهاء الكائن المنهائي ، وهذا هو ، يتم إدراج قائمة الانتظار بعد اللحظة الأخيرة التي يمكن فيها أداء الكائن عن عمليات معينة ، لذلك تكون آمنة على الإطلاق. إذا استطعت ، فيجب استخدام المراجع الافتراضية دائمًا ، لأن المراجع الأخرى سيكون لها إمكانية وضع اللمسات الأخيرة على استخدام الأساليب كائنات قابلة للإنهاء.
فكر في مثال على مدير الموارد الذي يمكنه التحكم في الوصول إلى مجموعات الموارد الخارجية. يمكن للكائنات أن تطلب الوصول إلى مورد خارجي ولا تنهي الوصول حتى يتم الانتهاء من العملية ، وبعد ذلك يجب عليها إعادة المورد المستخدم إلى مدير الموارد. إذا تمت مشاركة هذا المورد ، فسيتم تمرير حقوق استخدامه بين كائنات متعددة ، وقد يتم تمريرها بين مؤشرات ترابط متعددة ، لذلك من الصعب علينا تحديد الكائن الذي هو آخر مستخدم لهذا المورد ، وبالتالي يصعب تحديد أي رمز سيكون مسؤولاً عن إرجاع هذا المورد. للتعامل مع هذا الموقف ، يمكن لمدير الموارد تحقيق إعادة تدوير تلقائي لهذا المورد من خلال ربط مورد لكائن خاص يسمى المفتاح. طالما يمكن الوصول إلى الكائن الرئيسي ، نعتقد أن هذا المورد لا يزال قيد الاستخدام ؛ طالما أنه يمكن جمع الكائن الرئيسي كقمامة ، سيتم إصدار المورد تلقائيًا. الرمز التالي هو تمثيل مجردة للموارد المذكورة أعلاه:
Interface Resource {void use (مفتاح الكائن ، الكائن ... args) ؛ إصدار باطل () ؛ }عند الحصول على مورد ، يجب توفير كائنه الرئيسي لمدير الموارد. بالنسبة لمثيل المورد الذي تم إرجاعه ، لا يمكن استخدام هذا المورد إلا إذا حصل على مفتاحه المقابل. هذا يضمن أنه بعد إعادة تدوير المفتاح ، لم يعد من الممكن استخدام مورده المقابل ، حتى لو كان كائن المورد الذي يمثل هذا المورد قد لا يزال متاحًا. لاحظ أن كائن المورد لا يخزن مرجعًا قويًا للكائن الرئيسي ، وهو أمر مهم لأن هذا يمنع الكائن الرئيسي من أن يصبح غير قابل للوصول ، مما يؤدي إلى عدم قدرة المورد. يمكن تداخل تنفيذ الموارد في مدير الموارد:
تقوم ResourceImpl static static static بتنفيذ مورد {int keyhash ؛ Boolean NeedsRelease = false ResourceImpl (مفتاح الكائن) {keyhash = system.IndIntityHashCode (مفتاح) ؛ // = قم بإعداد مورد الخارجي احتياجات الموارد = صواب ؛ } استخدام الفراغ العام (مفتاح الكائن ، الكائن ... args) {if (system.identityHashCode (key)!! = keyhash) رمي illeqalargumentexception جديد ("مفتاح خاطئ" //...يتم تخزين رمز التجزئة للكائن الرئيسي عند إنشاء المورد ، وكلما تم استدعاء طريقة الاستخدام ، فإنه يتحقق مما إذا كان يتم توفير نفس المفتاح. قد يتطلب الاستخدام الفعلي للموارد أيضًا التزامن ، ولكن من أجل البساطة ، نحذفها هنا. طريقة الإصدار هي المسؤولة عن إطلاق المورد. يمكن استدعاؤه مباشرة من قبل مستخدم المورد بعد الاستخدام ، أو بواسطة مدير الموارد عندما لم يعد الكائن الرئيسي المشار إليه. نظرًا لأننا سنستخدم مؤشرات ترابط مستقلة لمراقبة قائمة الانتظار المرجعية ، يجب مزامنة طريقة الإصدار ويجب السماح بالمكالمات المتعددة.
مدير الموارد الفعلي لديه النموذج التالي:
الموارد الموارد العامة النهائية {Final Referenceueue
يمكن أن يكون الكائن الرئيسي أي كائن ، مما يمنح مستخدمي الموارد مرونة كبيرة مقارنة بوجود مدير الموارد كائنات رئيسية. عند استدعاء طريقة getResource ، سيتم إنشاء كائن MPL جديد للموارد ، وسيتم تمرير المفتاح المقدم للطريقة إلى كائن ResourceImpl الجديد. ثم يتم إنشاء مرجع افتراضي ، وكائنه المرجعي هو المفتاح الذي تم تمريره إلى الطريقة ، ثم سيتم إدراج هذا المرجع الافتراضي في قائمة انتظار مرجع مدير الموارد. سيتم تخزين الكائنات المرجعية الافتراضية والمرجعية التي تم إنشاؤها في النهاية في جدول التعيين. يحتوي جدول التعيين هذا على غرضان: أحدهما هو الحفاظ على جميع الكائنات المرجعية الافتراضية قابلة للوصول ، والآخر هو توفير طريقة مريحة للاستعلام عن كائن المورد الفعلي المرتبط بكل مرجع افتراضي. (البديل هو الفئة الفرعية الوهمية وتخزين كائن المورد في حقل.)
إذا أصبح الكائن الرئيسي غير قابل للوصول ، فإن مدير الموارد يستخدم مؤشر ترابط "Reaper" منفصل لمعالجة المورد. طريقة إيقاف التشغيل "إغلاق" المستكشف عن طريق إنهاء موضوع الحصاد (استجابةً للمقاطعة) ، مما تسبب في طريقة getResource لإلقاء استثناء ille-llllestateException. في هذا التصميم البسيط ، لن تتم معالجة أي مراجع توصيل قائمة انتظار بعد إغلاق المستكشف. موضوع الحصاد الفعلي كما يلي:
Class ReaperThread يمتد Thread {public void run () {// Run حتى يتم مقاطعة بينما (true) {try {Reference ref = queue.remove () ؛ Resource Res = null ؛ Synchronized (ResourceManager.This) {res = refs.get (Ref) ؛ الحكام. إزالة (المرجع) ؛ } res .release () ؛ Ref.Clear () ؛ } catch (interruptedException ex) {break ؛ // all done}}}}REAPERTHREAD هي فئة داخلية ، وسيتم تشغيل خيط الحصاد المعطى حتى يتم إغلاق مدير الموارد. يحجب مؤشر الترابط على طريقة إزالة حتى يتم إدراج المرجع الظاهري المرتبط بمفتاح معين في قائمة الانتظار المرجعية. يمكن لهذا المرجع الافتراضي الحصول على مرجع إلى كائن المورد من جدول التعيين ، ثم تتم إزالة هذا الزوج "الرئيسي إلى المرجع" من جدول التعيين. بعد ذلك مباشرة ، يتم استدعاء طريقة إصدارها على كائن المورد لإصدار المورد. في النهاية ،
يتم مسح المرجع الافتراضي بحيث يمكن إعادة تدوير المفتاح.
كبديل لاستخدام مؤشرات الترابط المستقلة ، يمكن استبدال أي عملية تستدعي طريقة الاستطلاع في قائمة الانتظار المرجعية وإطلاق جميع الموارد التي أصبحت مفاتيحها غير قابلة للوصول بطريقة GetResource "، ويمكن أيضًا استخدام طريقة الإغلاق" لأداء عملية الاستطلاع النهائية. تعتمد دلالات مدير الموارد على نوع المورد الفعلي ونمط استخدام الموارد.
التصميمات التي تستخدم قوائم الانتظار المرجعية أكثر موثوقية بكثير من التصميمات التي تستخدم الإنهاء مباشرة (وخاصة المراجع الافتراضية). لكننا بحاجة إلى أن نتذكر أن الوقت والموقع الدقيق للكائن المرجعي الذي تم إدخاله في قائمة الانتظار المرجعية غير مؤكد ، كما أننا لسنا متأكدين مما إذا كانت جميع المراجع القابلة للتجميع قد تم إدراجها في قائمة الانتظار المرجعية عندما ينتهي التطبيق. إذا احتجنا إلى التأكد من أنه يمكن إصدار جميع الموارد قبل أن ينتهي التطبيق ، فيجب علينا تثبيت خطاف الإغلاق اللازم أو استخدام بروتوكولات أخرى محددة من قبل التطبيق لضمان تحقيق ذلك.