جافا: كيف تفعل قفل مزدوج مع عنصر صفيف؟
-
29-09-2019 - |
سؤال
هذا ما يبدو عليه الكود الخاص بي حاليًا:
private boolean[] isInitialized = new boolean[COUNT];
private void ensureInitialized(int i) {
if (! isInitialized[i]) {
initialize(i);
isInitialized[i] = true;
}
}
الآن أريد أن أحصل على مؤشر ترابط. أعلم أن القفل المزدوج في جافا هو "Teh 3Vilness !! 1" ، ولكن منذ ذلك الحين ensureInitialized
قد يتم استدعاؤها في كثير من الأحيان ، لا أريد أن تتم مزامنتها. لذلك أنا أفكر في القيام بذلك:
private boolean[] isInitialized = new boolean[COUNT];
private void ensureInitialized(int i) {
if (! isInitialized[i]) {
synchronized (this) {
if (! isInitialized[i]) {
initialize(i);
isInitialized[i] = true;
}
}
}
}
الآن ماذا علي أن أفعل لجعل هذا الموضوع آمنًا في الواقع؟
بعض الاختبارات الفرعية:
- تحضير
isInitialized
المتقلبة ليست ضرورية ، لأن المتغير لم يتغير ، أليس كذلك؟ - تم تغيير عناصر الصفيف ، كيف يمكنني جعل تلك المتقلبة؟
- هل هناك طرق أفضل بشكل عام للقيام بذلك؟
(لاحظ أيضًا أن هذه طريقة مثيل ، لذلك لن يعمل التهيئة الثابتة)
المحلول
يرجى ملاحظة أن تنفيذ Java للمتحقق المزدوج يسمى "النمط المكسور" لأنه ثبت أنه فشل (على سبيل المثال انظر http://www.cs.umd.edu/~pugh/java/memorymodel/doubleCheckedLocking.html). للعمل حول فقط استخدام العملية الذرية. اتبع هو نموذج كيفية بناء موضوع آمن سينغليتون:
static AtomicReferenceArray<Boolean> instance =
new AtomicReferenceArray<Boolean>(COUNT);
private void ensure(int i)
{
if(!instance.get(i) )
{
synchronized(this){
if( !instance.get(i) ){
initialize(i);
instance.set(i, true);
}
}
}
نصائح أخرى
يمكنك أيضًا التفكير في استخدام Suppliers.memoize(Supplier<T> delegate)
من مكتبة الجوافة.