Java.util.ConcurrentModificationException - Problema com concorrência

Olá pessoal!!! Preciso da ajuda de vocês para resolver um problema de concorrência que estou tendo aqui no serviço.

Estou fazendo um aplicativo de monitoramento de frente de caixa. Este aplicativo recebe o status dos caixas via socket e guarda as conexões em um HashMap. O aplicativo possui uma thread servidora que recebe as conexões dos caixas e para cada caixa conectado é criada uma nova thread independente que fica trocando os icones dependendo do status. Quando um caixa se desconecta, a thread servidora remove da lista esta conexão só que enquanto isso as outras threads estão lendo a lista procurando cada uma o seu caixa e isso está causando java.util.ConcurrentModificationException Estou com dificuldades para sincronizar o código e não estou conseguindo resolver, se puderem me ajudar, segue abaixo os códigos:

1 - Thread Servidora

public class MonitoringServer extends Thread {

	private HashMap<String, PDV> pdvsConectados = new HashMap<String, PDV>();

	@Override
	public void run() {

		ServSocket ss = new ServSocket(4400);

		System.out.println("Iniciando Servidor de monitoramento...");

		ss.setTimeAlive(10000); // 10 segundos para checagem de conexao
		ss.setIgnoreMsgAlive(false);
		ss.setIgnoreMsgException(false);
		ss.setAutoCriptografia(false);
		ss.setAutoCheckSum(false);
		ss.start();

		System.out.println("Servidor iniciado!");

		int contador = 1000;

		while (ss.isAlive()) {

			try {
				Thread.sleep(1);
			} catch (Exception e) {
			}

			if (ss.getBufferSize() > 0) {
				receberMensagem(ss);
			}

			if (--contador == 0) {
				contador = 1000;
				verificarConexoes(ss);
			}

		}

		System.out.println("Servidor de monitoramento encerrado!");

	}

	private void verificarConexoes(ServSocket ss) {

		ArrayList<String> conexoes = new ArrayList<String>();

		System.out.println("PDVs conectados: " + ss.getConnections());

		for (int i = 0; i < ss.getConnections(); i++) {
			conexoes.add(ss.getConnection(i).getSocket()
					.getRemoteSocketAddress().toString());
		}

		synchronized (pdvsConectados) {

			for (String key : pdvsConectados.keySet()) {
				String addr = pdvsConectados.get(key).getEndereco();
				if (!conexoes.contains(addr)) {
					pdvsConectados.remove(key);
				}
			}
			
			pdvsConectados.notifyAll();

		}

	}

	private void receberMensagem(ServSocket ss) {
		
		PDV pdv = parseMessage(ss.getBufferSocket().getBuffer());
		// guardando o endereço IP do pdv
		pdv.setEndereco(ss.getBufferSocket().getSocket()
				.getRemoteSocketAddress().toString());
		// guardando no hash de pdvs
		synchronized (pdvsConectados) {
			
			pdvsConectados.put(pdv.toString(), pdv);
			pdvsConectados.notifyAll();
			
		}
		
		ss.removeFromBuffer();
		
	}

	private PDV parseMessage(String msg) {
		/*
		 * Exemplo 1:1:12 Loja 1 PDV 1 Código da mensagem 12
		 */
		String[] msgp = msg.split(":");
		PDV pdv = new PDV(Integer.parseInt(msgp[0]), Integer.parseInt(msgp[1]),
				"F");
		// guardando a mensagem do PDV
		pdv.setCodigoMensagem(Integer.parseInt(msgp[2]));
		return pdv;
	}

// este método é acessado por outras Threads, cada uma buscando o seu PDV
	public synchronized PDV getPdv(int loja, int codigo) {
		synchronized (pdvsConectados) {
			try {
//				pdvsConectados.wait();
				return pdvsConectados.get(new PDV(loja, codigo, "").toString());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
		}
	}

}

2 - Método run das Threads que acessam a lista

@Override
public void run() {
	while (true) {
		try {
			Thread.sleep(2000);
		} catch (Exception e) {
		}
// GzMonitoring.SERVER é uma instância da Thread servidora
		PDV pdv = GzMonitoring.SERVER.getPdv(loja, codigo);
		int message = 0;
		try {
			message = pdv.getCodigoMensagem();
		} catch (Exception e) {
			setIcon(iconOffline);
			continue;
		}
		setIcon(MessageCodes.getIcon(message));
	}
}

Muito obrigado!

for (String key : pdvsConectados.keySet()) { String addr = pdvsConectados.get(key).getEndereco(); if (!conexoes.contains(addr)) { pdvsConectados.remove(key); } }

aqui está seu possivel erro, não pode remover algo de uma collection quando a mesma está sendo iterada,

oque pode ser feito e copiar essa collection, iterar com a original e remover a copia

valew

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.html