2017-12-05 4 views
0
public class RetryHandler extends Thread { 

private ArrayList<RetryMessage> retryMessages; 
private Object syncObject = new Object(); 

private RetryHandler() { 
    this.setName("retryhlr"); 
} 
public Boolean addMessage(IfgExchangeRequestBase msg, int token) { 
    synchronized(syncObject) { 
     retryMessages.add(new RetryMessage(msg, token)); 
     return true; 
    } 
} 

public Boolean removeMessage(Integer token) { 
    synchronized(syncObject) { 
     retryMessages.removeIf(x->x.getToken().equals(token)); 
     return true; 
    } 
} 

@Override 
public void run() { 
    while(isRunning) { 
     if (!isPaused) { 
      synchronized(syncObject) { 
       ListIterator<RetryMessage> tempRTMessages = retryMessages.listIterator(); 
       while(tempRTMessages.hasNext()){ 
        RetryMessage rtmsg =tempRTMessages.next(); 
        if(....)) { 
         tempRTMessages.remove(); 
        } else if(...) 
         try { 
          int token = fetch() 
          rtmsg.retried(); 
          rtmsg.setToken(token); 
         } catch (SAGException e) { 
        } 
       } 
      } 
     } 
    } 
} 

}ConcurrentModificationException trotz der Verwendung von Iterator und synchronisiert

Wie Sie sehen RetryHandler Gewinde erstreckt, die retryMessages über eine interne Liste iterieren. Trotz der Verwendung Iterator und synchronized bekomme ich ConcurrentModificationException. addMessage und removeMessage wurde in anderen Threads verwendet.

hinweis: I Verwendet ListIterator aber das ergebnis ist das selbe. und RetryMessage rtmsg =tempRTMessages.next(); löst diese Ausnahme aus. enter image description here

UPDATE: Exception wirft auf RetryMessage rtmsg =tempRTMessages.next();

+3

Sind Sie sicher, dass die '' retryMessages' list' nur über die 'addMessage' modifiziert und' removeMessage' Methoden? – Eran

+0

Was macht 'fetch()'? –

+1

Beachten Sie, dass es eine gute Idee ist, die endgültigen Mitglieder zu synchronisieren, damit Sie sie nicht versehentlich neu zuweisen können. –

Antwort

0

Sie sind wegen der Ausnahme der Fehler stoßen, weil Sie die Arraylist iterieren, und es während laufen, sind Sie Objekte daraus zu entfernen. Dies ist ein fail-fast-Mechanismus für diese Art von Sammlung.

Was Sie tun können, wenn Sie wirklich Elemente aus der ArrayList entfernen müssen, ist ein CopyOnWriteArrayList-Objekt zu erstellen, dieses Objekt ist das, was Sie tun werden. Bitte beachten Sie den Code unten:

CopyOnWriteArrayList<RetryMessage> retryMessageCopyOnWrite= new CopyOnWriteArrayList<RetryMessage>(retryMessages); 
    Iterator<RetryMessage> retryMessageIterator = retryMessageCopyOnWrite.iterator(); 
... 
<some object modifications here for retryMessageCopyOnWrite> 

Dann kopieren Sie einfach den Inhalt des CopyOnWriteArrayList auf das retryMessages Liste Objekt wieder auf die ursprüngliche Arraylist.

Da Sie auch den Iterator selbst verwenden, um ein Element zu entfernen. Bitte lesen Sie diesen Link:

Ich schlage eine alternative Möglichkeit vor, die Liste zu ändern, anstatt den Iterator selbst zu verwenden, verwenden Sie das CopyOnWriteArrayList-Objekt.

Sie können innerhalb der Iteration etwas wie dieses:

RetryMessage temp = iterator.next(); 
if(do some checking) { 
    retryMessageCopyOnWrite.remove(temp); //this removes the current element 
} 
+0

warum Iterator ''? –

+1

Ich änderte es in Iterator GemSky

+0

Ich änderte meinen Code aber: 'Ausnahme im Thread" retryhlr "java.lang.UnsupportedOperationException \t bei java.util.concurrent.CopyOnWriteArrayList $ COWIterator.remove (CopyOnWriteArrayList.java:1176) \t bei RetryHandler.run (RetryHandler.java:98) ' –

Verwandte Themen