سؤال

في تطبيق متعددة الخيوط أنا أعمل على أننا نرى في بعض الأحيان ConcurrentModificationExceptions على قوائم (التي هي في معظمها ArrayList, أحيانا ناقلات).ولكن هناك أوقات أخرى عندما أفكر المتزامنة التعديلات يحدث لأن بالتكرار من خلال جمع يبدو أن العناصر المفقودة ، ولكن لم يتم طرح الاستثناءات.وأنا أعلم أن المستندات ConcurrentModificationException يقول لك لا يمكن الاعتماد على ذلك ، ولكن كيف يمكنني التأكد من أنني لست بالتزامن تعديل قائمة ؟ و هو التفاف كل الوصول إلى مجموعة متزامنة كتلة الطريقة الوحيدة لمنع ذلك ؟

تحديث: نعم, أنا أعرف عن Collections.synchronizedCollection, لكن هذا لا حارس ضد شخص تعديل جمع حين كنت بالتكرار من خلال ذلك.أعتقد أن على الأقل بعض من مشكلتي يحدث عندما شخص يضيف شيئا إلى مجموعة بينما أنا بالتكرار من خلال ذلك.

التحديث الثاني إذا كان شخص ما يريد أن الجمع بين ذكر synchronizedCollection و الاستنساخ مثل جيسون فعلت مع ذكر جافا.util.متزامنة أباتشي مجموعات الأطر مثل jacekfoo و Javamann هل أستطيع تقبل إجابة.

هل كانت مفيدة؟

المحلول

سؤالك الأصلي ويبدو أن يسأل عن التكرار الذي يرى التحديثات الحية الكامنة جمع في حين تبقى مؤشر الترابط-الآمن.هذا هو باهظة الثمن بشكل لا يصدق مشكلة حل في الحالة العامة ، وهذا هو السبب أيا من معيار جمع الصفوف تفعل ذلك.

هناك الكثير من الطرق لتحقيق الحلول الجزئية أن المشكلة في التطبيق الخاص بك, واحدة من هذه قد تكون كافية.

جيسون يعطي طريقة معينة لتحقيق موضوع السلامة وتجنب رمي ConcurrentModificationException, ولكن فقط على حساب liveness.

Javamann يذكر اثنين فئات محددة في java.util.concurrent حزمة حل نفس المشكلة في قفل-طريقة مجانية ، حيث قابلية أمر بالغ الأهمية.هذه فقط التي يتم شحنها مع جافا 5 ، ولكن كان هناك العديد من المشاريع التي backport وظائف الحزمة في وقت سابق من إصدارات جافا ، بما في ذلك هذا واحد, ، على الرغم من أنها لن يكون لها مثل هذا الأداء الجيد في وقت سابق JREs.

إذا كنت تستخدم بالفعل بعض أباتشي العموم المكتبات ، ثم jacekfoo يشير, ، أباتشي مجموعات إطار يحتوي على بعض دروس مفيدة.

كنت قد تنظر أيضا في النظر في جوجل مجموعات إطار.

نصائح أخرى

اعتمادا على تحديث التردد واحدة من المفضلة هي CopyOnWriteArrayList أو CopyOnWriteArraySet.إنشاء قائمة جديدة/مجموعة على التحديثات لتجنب المتزامنة تعديل استثناء.

تحقق من java.util.المتزامنة عن الإصدارات القياسية مجموعات الطبقات التي صممت للتعامل مع التزامن بشكل أفضل.

نعم لديك لمزامنة الوصول إلى مجموعات الكائنات.

بدلا من ذلك, يمكنك استخدام متزامنة مغلفة حول أي كائن موجود.انظر مجموعات.synchronizedCollection().على سبيل المثال:

List<String> safeList = Collections.synchronizedList( originalList );

ومع كل قانون يحتاج إلى استخدام النسخة آمنة ، حتى بالتكرار بينما مؤشر ترابط آخر تعديل سوف يؤدي إلى مشاكل.

حل مشكلة التكرار, نسخ القائمة الأولى.على سبيل المثال:

for ( String el : safeList.clone() )
{ ... }

لمزيد من الأمثل ، مؤشر الترابط-الآمن مجموعات, ننظر أيضا في java.util.المتزامنة.

عادة ما تحصل على ConcurrentModificationException إذا كنت تحاول إزالة عنصر من قائمة بينما يجري يتحرك من خلال.

أسهل طريقة لاختبار هذا هو:

List<Blah> list = new ArrayList<Blah>();
for (Blah blah : list) {
     list.remove(blah); // will throw the exception
}

أنا لست متأكدا كيف كنت تحصل من حوله.قد تضطر إلى تنفيذ الخاص بك مؤشر الترابط-الآمن قائمة ، أو يمكنك إنشاء نسخ من القائمة الأصلية للكتابة و متزامنة الفئة التي يكتب إلى القائمة.

قد تتمكن من محاولة استخدام دفاعية النسخ بحيث التعديلات واحد List لا تؤثر على الآخرين.

التفاف يصل إلى جمع في مزامنة كتلة هي الطريقة الصحيحة للقيام بذلك.البرمجة القياسية الممارسة يملي استخدام نوع من قفل آلية (إشارة, مزامنة, الخ) عند التعامل مع الدولة التي يتم مشاركتها عبر العديد من المواضيع.

اعتمادا على حالة الاستخدام ولكن يمكنك عادة ما جعل بعض التحسينات فقط قفل في بعض الحالات.على سبيل المثال, إذا كان لديك مجموعة التي كثيرا ما قرأت ولكن نادرا ما كتبت, ثم يمكنك السماح المتزامنة يقرأ ولكن فرض قفل كلما أكتب في التقدم.المتزامنة يقرأ فقط تسبب الصراعات إذا جمع هي في طور التعديل.

ConcurrentModificationException هو أفضل جهد لأن ما تطلبه هو مشكلة صعبة.لا توجد طريقة جيدة للقيام بذلك موثوق دون التضحية بالأداء إلى جانب إثبات أن الوصول إلى أنماط لا بالتزامن تعديل قائمة.

تزامن المرجح أن تمنع المتزامنة التعديلات, و قد يكون ما كنت تلجأ إلى في نهاية المطاف, لكنه في نهاية الأمر مكلفا.أفضل شيء نفعله هو الأرجح إلى الجلوس والتفكير لبعض الوقت عن خوارزمية الخاص بك.إذا كنت لا يمكن أن تأتي مع قفل-حل مجاني ، ثم اللجوء إلى التزامن.

انظر التنفيذ.انها في الأساس مخازن الباحث:

transient volatile int modCount;

وأن يتزايد عندما يكون هناك 'التعديل الهيكلي' (مثل إزالة).إذا كان مكرر بالكشف عن أن modCount تغييره يلقي المتزامنة تعديل استثناء.

مزامنة (عبر مجموعات.synchronizedXXX) لن تفعل جيدا لأنه لا يضمن مكرر السلامة فقط مزامنة يكتب ويقرأ عبر وضع, على, مجموعة ...

انظر جافا.util.concurennt أباتشي مجموعات إطار (له بعض الفئات التي هي الأمثل لا تعمل بشكل صحيح في المتزامنة البيئة عندما يكون هناك المزيد من يقرأ (التي هي غير المتزامنة) من يكتب - انظر FastHashMap.

يمكنك أيضا مزامنة أكثر من iteratins أكثر من قائمة.

List<String> safeList = Collections.synchronizedList( originalList );

public void doSomething() {
   synchronized(safeList){
     for(String s : safeList){
           System.out.println(s);

     }
   }

}

هذا قفل قائمة على تزامن منع جميع المواضيع التي تحاول الوصول إلى قائمة أثناء تحريره أو تكرار أكثر من ذلك.الجانب السلبي هو أن خلق لكم من عنق الزجاجة.

وهذا يوفر بعض الذاكرة أكثر .طريقة استنساخ() و قد يكون أسرع اعتمادا على ما تفعله في التكرار...

مجموعات.synchronizedList() سيتم تقديم قائمة اسميا مؤشر الترابط-الآمن و جافا.util.المتزامنة لديه المزيد من الميزات القوية.

هذا سوف تحصل على التخلص من المتزامنة تعديل استثناء.لن أتكلم كفاءة ومع ذلك؛)

List<Blah> list = fillMyList();
List<Blah> temp = new ArrayList<Blah>();
for (Blah blah : list) {
     //list.remove(blah);  would throw the exception
     temp.add(blah);
}
list.removeAll(temp);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top