لماذا يعد ConcurrentHashMap.putifAbsent آمنًا؟
-
13-11-2019 - |
سؤال
لقد كنت أقرأ من أجل التزامن منذ الأمس ولا أعرف الكثير من الأشياء ...لكن بعض الأمور بدأت تتضح..
أفهم لماذا لا يكون قفل التحقق المزدوج آمنًا (أتساءل ما هي احتمالية حدوث حالة نادرة) ولكن التقلب يعمل على إصلاح المشكلة في 1.5 +....
لكني أتساءل عما إذا كان هذا يحدث مع putifAbsent
يحب...
myObj = new myObject("CodeMonkey");
cHashM.putIfAbsent("keyy",myObj);
ثم هل هذا يضمن ذلك myObj
سيتم البادئة بنسبة 100٪ عندما يقوم مؤشر ترابط آخر بـ cHashM.get()
؟؟؟؟لأنه قد يحتوي على مرجع لم تتم تهيئته بالكامل (مشكلة قفل التحقق المزدوج)
المحلول
إذا استدعيت concurrentHashMap.get(key)
وتقوم بإرجاع كائن، ويتم ضمان تهيئة هذا الكائن بالكامل.سيحصل كل وضع (أو putIfAbsent) على قفل خاص بالدلو وسيقوم بإلحاق العنصر بإدخالات الجرافة.
يمكنك الآن الاطلاع على الكود وملاحظة أن طريقة get لا تحصل على نفس القفل.لذلك يمكنك القول بأنه يمكن أن تكون هناك قراءة قديمة، وهذا ليس صحيحًا أيضًا.والسبب هنا هو أن القيمة داخل الإدخال نفسه متقلبة.لذلك سوف تكون متأكدًا من حصولك على أحدث المعلومات.
نصائح أخرى
putIfAbsent
طريقة في ConcurrentHashMap
هي طريقة التحقق من الغياب ثم التعيين.إنها عملية ذرية.ولكن للإجابة على الجزء التالي:"ثم هل يضمن هذا أن myObj سيتم تمهيده بنسبة 100٪ عندما يقوم مؤشر ترابط آخر بإجراء cHashM.get() "، سيعتمد ذلك على وقت وضع الكائن في HashMap.عادةً ما تكون هناك أسبقية "حدث قبل"، أي إذا حصل المتصل على الأولوية قبل وضع الكائن في الخريطة، إذن null
سيتم إرجاعها، وإلا سيتم إرجاع القيمة.
الجزء ذو الصلة من الوثائق هو هذا:
تأثيرات تناسق الذاكرة:كما هو الحال مع المجموعات المتزامنة الأخرى ، فإن الإجراءات الموجودة في مؤشر ترابط قبل وضع كائن في خريطة متزامنة كمفتاح أو قيمة حدث قبل الوصول إلى الوصول أو إزالة هذا الكائن من ConcurrentMap في مؤشر ترابط آخر.
لذا، نعم لديك الخاص بك يحدث من قبل علاقة.
أنا لست خبيرا في هذا، ولكن أبحث في التنفيذ Segment
في ConcurrentHashMap
أرى أن volatile
مجال count
يبدو أنه يستخدم لضمان الرؤية المناسبة بين المواضيع.جميع عمليات القراءة يجب أن تقرأ count
الحقل وجميع عمليات الكتابة يجب أن تكتب إليه.من التعليقات في الصف:
Read operations can thus proceed without locking, but rely on selected uses of volatiles to ensure that completed write operations performed by other threads are noticed. For most purposes, the "count" field, tracking the number of elements, serves as that volatile variable ensuring visibility. This is convenient because this field needs to be read in many read operations anyway: - All (unsynchronized) read operations must first read the "count" field, and should not look at table entries if it is 0. - All (synchronized) write operations should write to the "count" field after structurally changing any bin. The operations must not take any action that could even momentarily cause a concurrent read operation to see inconsistent data. This is made easier by the nature of the read operations in Map. For example, no operation can reveal that the table has grown but the threshold has not yet been updated, so there are no atomicity requirements for this with respect to reads.