연결 목록이있는 서버 응용 프로그램이 있습니다. 이 프로그램은 여러 스레드를 사용합니다. 주 스레드는 간격을두고 프로세스를 실행하여 닫힌 연결을 감지 한 다음 배열에서 제거하여 가비지 수집 할 수 있도록합니다.HashMap에서 항목을 제거하면 ConcurrentModificationException이 발생합니다.
이 과정은 다음과 같다 :
private void cullOtherProcessors() throws Exception {
//log.log(Level.FINE,"XMLMessageReciever:cullOtherProcessors");
List<ConnectionAppInterface> toDel = new ArrayList<ConnectionAppInterface>();
for (ConnectionAppInterface cur : m_OtherProcessors.keySet()) {
if (cur!=null) {
if (cur.isClosed()) {
//Connection is closed - we could never send a message over it
toDel.add(cur);
}
}
}
for (int c=0;c<toDel.size();c++) {
log.log(Level.FINE,"**XMLMessageReciever:cullOtherProcessors - removing closed connection");
m_OtherProcessors.remove(toDel.get(c));
}
}
내 서버가 몇 달에 출마하지만 다음과 같은 오류와 함께 추락 로그에 따라 :
기본적으로08/10/16 01:06:39 calling connect
08/10/16 01:06:39 **XMLMessageReciever:cullOtherProcessors - removing closed connection
08/10/16 01:06:39 CloseableThread: End of run for thread Socket.Connect(113726)
08/10/16 01:06:39 Checking connected
08/10/16 01:06:39 Active Threads this group: 5
08/10/16 01:06:39 getting Message Reciever
08/10/16 01:06:39 Active Threads: 8
08/10/16 01:06:39 Setting m_establishingCon
08/10/16 01:06:39 Establishing connection to robertsNode
Server Failed
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
at java.util.HashMap$KeyIterator.next(HashMap.java:1453)
at metcarob.com.common.network.xmlprotocol.XMLMessageReciever.cullOtherProcessors(XMLMessageReciever.java:57)
at metcarob.com.common.network.xmlprotocol.XMLMessageReciever.LoopIteration(XMLMessageReciever.java:98)
at metcarob.com.common.network.xmlprotocol.ConnectionManager.LoopIteration(ConnectionManager.java:48)
at metcarob.com.personalservices.singlenodeserver.Main.run(Main.java:138)
at metcarob.com.personalservices.singlenodeserver.Main.main(Main.java:398)
뭔가 ArrayList에 일어난 nextNode가 예외를 던지게하면서 (아마도 다른 연결이 설정되어) 반복하면서 루프를 돌고있었습니다.
나는 주변을 둘러 볼 수있는 가장 좋은 방법을 찾으려고 노력 중이다. 나는 단순히 오류를 포착하고 무시하는 것을 고려하고있다. 누락 된 스레드는 단순히 다음 루프에서 제거됩니다. 제안 된 솔루션은 다음과 같습니다.
private void cullOtherProcessors() throws Exception {
//log.log(Level.FINE,"XMLMessageReciever:cullOtherProcessors");
//m_OtherProcessors
List<ConnectionAppInterface> toDel = new ArrayList<ConnectionAppInterface>();
try {
for (ConnectionAppInterface cur : m_OtherProcessors.keySet()) {
if (cur!=null) {
if (cur.isClosed()) {
//Connection is closed - we could never send a message over it
toDel.add(cur);
}
}
}
} catch (ConcurrentModificationException e) {
log.log(Level.FINE,"**XMLMessageReciever:cullOtherProcessors - ConcurrentModificationException being ignored");
}
for (int c=0;c<toDel.size();c++) {
log.log(Level.FINE,"**XMLMessageReciever:cullOtherProcessors - removing closed connection");
m_OtherProcessors.remove(toDel.get(c));
}
}
이제이 코드를 다시 서버에 저장하고 더 오랫동안 실행합니다.
이 문제에 대한 좋은 해결책인지 알고 싶습니다. 처음부터이 문제가 발생하기까지 수개월이 걸렸고 5 분마다 코드가 연결을 반복하므로 연결이 자주 끊어지지 않을 확률이 적다는 생각이 듭니다. (로그를보고 볼 것입니다)
전문가가 생각하는 것이 좋을 것입니다.
** 그것은이 질문에 제안되었다
그것은 아니다 "루프에서 제거 할 때, 컬렉션을 반복하는 ConcurrentModificationException를 피"와 동일합니다. 내 코드에서는 HashMap을 반복하면서 항목을 제거하지 않고 대신 맵을 반복하고 제거 할 항목을 임시 Array에 저장합니다. 그런 다음 배열을 통해 항목을 제거합니다.
어머, 예외를 무시하는 것은 쉬운 일이 아닙니다. 이 장치를 추출하고 스레드로 문제를 재현하려 했습니까? 당신이 동일한 데이터 구조를 읽고 쓰고 있기 때문에 나는 경쟁 조건을 보았습니다. syncronisation없이 m_OtherProcessors를 – Paolof76
m_OtherProcessors를 생성하는 곳은 어디입니까 ?? –
오류가 멀티 스레딩과 관련이 있습니까? ConcurrentModificationException은 스레드와 관련이 없습니다. 다중 스레딩으로 인해 발생하는 경우 오류를 잡아도 동시 데이터 구조를 사용하지 않아도되는 결과를 피할 수는 없습니다. –