سؤال

ها هي مشكلتي:

هذه القطعة من الكود ترمي أ java.util.ConcurrentModificationException, ، بسبب ال Vector listeners يتم تعديله أثناء وجوده Iterator لهذا بنية البيانات. يقول Java-Doc أن هذه الحاوية لا توفر سوى موعد فاشل سريع.

هل هناك إمكانية للحصول على Iterator على حاوية قياسية مثل Vector أو List في جافا التي تقدم لي Iterator, ، لا يصبح هذا غير صالح (ليس سريع الفشل) ، إذا كان هناك عنصر تم إزالته خلال ذلك Iterator "الأرواح"؟

يجب أن يكون لدي نفس السلوك مثل std::list في C ++. هناك يكون المكرر صالحًا دائمًا حتى إذا تم إزالة التكرار الحالي. من يتم تعيين التكرار على العنصر التالي في القائمة.

public class ClientHandle {
private final Vector<ClientHandleListener> listeners = new Vector<ClientHandleListener>();


public synchronized void  addListener(ClientHandleListener chl) {
    listeners.add(chl);
}

public synchronized void  removeListener(ClientHandleListener chl) {
    listeners.remove(chl); 
}

private void fireConnectionClosed() {
    final ClientHandle c = this;

    final Iterator<ClientHandleListener> it = listeners.iterator();
    new Thread(){
        @Override
        public void run() {
            while (it.hasNext()) {
                it.next().connectionClosed(c); //FIXME the iterator gets modified 
            }
            };
    }.start();
}}

public class ClientHandlePool implements ClientHandleListener, TaskManagerListener {

        /*...*/
    public synchronized void  removeClientHandle(ClientHandle ch) {
                //here the listeners Vector from the ClientHandle gets modified
        ch.removeListener(this); 
        ch.removeListener(currentListener);
        clientHandles.remove(ch);
    }

    @Override
    public void connectionClosed(ClientHandle ch) {
        removeClientHandle(ch);
    }
}
هل كانت مفيدة؟

المحلول

بقدر ما أعرف أنه لا توجد طريقة لإضافة تلك القدرة بأثر رجعي إلى أي افتراضي Collection التنفيذ (Iterable حقيقة).

ولكن هناك تطبيقات تدعم هذا النوع من السلوك من خلال استجابات محددة جيدًا للتعديل المتزامن أثناء التكرار.

مثال واحد هو CopyOnWriteList.

نصائح أخرى

في حالة المستمعين ، قد تفكر في استخدام java.util.concurrent.CopyOnWriteArrayList كما يكون لديك عادة المزيد من القراءات من الكتابة.

إلقاء نظرة على حزمة java.util.concurrent ستجد كل ما تحتاجه.

طريقة كسول لإنشاء تكرار سريع آمن من الفشل: خذ نسخة من القائمة كصفيف أثناء قفله ، و foreach () على الصفيف أثناء فتحه ... يمكن القيام به مع أي نوع من القائمة

private void fireConnectionClosed() {
   final ClientHandle c = this;

   final ClientHandleListener[] listenersArr;
   synchronized(this) {
       listenersArr=listeners.toArray(new ClientHandleListener[0]);
   }
   new Thread(){
       @Override
       public void run() {
          for(ClientHandleListener listener : listenersArr )
              listener.connectionClosed(c);
          }
       };
   }.start();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top