Map change during iteration on its input

In the java docs of the interface method of the entrySet () interface of the map, I found this expression, and I really don't understand it.

The set is supported by the map, therefore changes in the map are reflected in the set and vice versa. If the map changes when iterating over the set, the results of the iteration are undefined

what is meant by undefined here?

For clarification, this is my situation.

I have a spring based web application and hibernate.

Our team has a custom caching class called CachedIntegrationClients.

We use RabbitMQ as a messaging server.

instead of receiving our clients every time we want to send a message to the server, we cache clients using the previous caching class.

The problem is that messages are sent to the messaging server twice.

Looking at the logs, we found that the method that receives cached clients returns the client twice, although this is (theoretically) impossible, since we store clients on the map, and the map does not allow duplicate keys.

After some look at the code smoke, I found that a method that iterates over cached clients gets a set of clients from the cached client map.

Thus, I suspected that when repeating this set, another request is made by another client, and this client may be closed, so it changes the map.

In any case, this is the class CachedIntegrationClients

public class CachedIntegrationClientServiceImpl {      Dao integrationDao;      IntegrationServiceService;

Map<String, IntegrationClient> cachedIntegrationClients = null;

@Override
public void setBaseDAO(BaseDao baseDao) {
    super.setBaseDAO(integrationDao);
}

@Override
public void refreshCache() {
    cachedIntegrationClients = null;
}

synchronized private void putOneIntegrationClientOnCache(IntegrationClient integrationClient){
    fillCachedIntegrationClients(); // only fill cache if it is null , it will never refill cache
    if (! cachedIntegrationClients.containsValue(integrationClient)) {
        cachedIntegrationClients.put(integrationClient.getClientSlug(),integrationClient);
    }
}

/**
 * only fill cache if it is null , it will never refill cache
 */
private void fillCachedIntegrationClients() {
    if (cachedIntegrationClients != null) {
        return ;
    }
    log.debug("filling cache of cachedClients");
    cachedIntegrationClients = new HashMap<String, IntegrationClient>(); // initialize cache Map
    List<IntegrationClient> allCachedIntegrationClients= integrationDao.getAllIntegrationClients();
    if (allCachedIntegrationClients != null) {
        for (IntegrationClient integrationClient : allCachedIntegrationClients) {
            integrationService
                    .injectCssFileForIntegrationClient(integrationClient);
            fetchClientServiceRelations(integrationClient
                    .getIntegrationClientServiceList());
        }
        for (IntegrationClient integrationClient : allCachedIntegrationClients) {
            putOneIntegrationClientOnCache(integrationClient);
        }
    }
}

/**
 * fetch all client service
 * @param integrationClientServiceList
 */
private void fetchClientServiceRelations(
        List<IntegrationClientService> integrationClientServiceList) {
    for (IntegrationClientService integrationClientService : integrationClientServiceList) {
        fetchClientServiceRelations(integrationClientService);
    }
}

private void fetchClientServiceRelations(IntegrationClientService clientService) {
    for (Exchange exchange : clientService.getExchangeList()) {
        exchange.getId();
    }
    for (Company company : clientService.getCompanyList()) {
        company.getId();
    }

}
/**
 * Get a client given its slug.
 * 
 * If the client was not found, an exception will be thrown.
 * 
 * @throws ClientNotFoundIntegrationException
 * @return IntegrationClient
 */
@Override
public IntegrationClient getIntegrationClient(String clientSlug) throws ClientNotFoundIntegrationException {
    if (cachedIntegrationClients == null) {
        fillCachedIntegrationClients();
    }

    if (!cachedIntegrationClients.containsKey(clientSlug)) {
        IntegrationClient integrationClient = integrationDao.getIntegrationClient(clientSlug);
        if (integrationClient != null) {
            this.fetchClientServiceRelations(integrationClient.getIntegrationClientServiceList());
            integrationService.injectCssFileForIntegrationClient(integrationClient);
            cachedIntegrationClients.put(clientSlug, integrationClient);
        }
    }

    IntegrationClient client = cachedIntegrationClients.get(clientSlug);
    if (client == null) {
        throw ClientNotFoundIntegrationException.forClientSlug(clientSlug);
    }
    return client;
}

public void setIntegrationDao(IntegrationDao integrationDao) {
    this.integrationDao = integrationDao;
}

public IntegrationDao getIntegrationDao() {
    return integrationDao;
}

public Map<String, IntegrationClient> getCachedIntegrationClients() {
    if (cachedIntegrationClients == null) {
        fillCachedIntegrationClients();
    }
    return cachedIntegrationClients;
}

public IntegrationService getIntegrationService() {
    return integrationService;
}

public void setIntegrationService(IntegrationService integrationService) {
    this.integrationService = integrationService;
}

}

,

public List<IntegrationClientService> getIntegrationClientServicesForService(IntegrationServiceModel service) {
        List<IntegrationClientService> integrationClientServices = new ArrayList<IntegrationClientService>();
        for (Entry<String, IntegrationClient> entry : cachedIntegrationClientService.getCachedIntegrationClients().entrySet()) {
            IntegrationClientService integrationClientService = getIntegrationClientService(entry.getValue(), service);
            if (integrationClientService != null) {
                integrationClientServices.add(integrationClientService);
            }
        }
        return integrationClientServices;
    }

,

List<IntegrationClientService> clients = integrationService.getIntegrationClientServicesForService(service);
    System.out.println(clients.size());
    if (clients.size() > 0) {
        log.info("Inbound service message [" + messageType.getKey() + "] to be sent to " + clients.size()
                + " registered clients: [" + StringUtils.arrayToDelimitedString(clients.toArray(), ", ") + "]");

        for (IntegrationClientService integrationClientService : clients) {
            Message<T> message = integrationMessageBuilder.build(messageType, payload, integrationClientService);
            try {
                channel.send(message);
            } catch (RuntimeException e) {
                messagingIntegrationService.handleException(e, messageType, integrationClientService, payload);
            }
        }
    } else {
        log.info("Inbound service message [" + messageType.getKey() + "] but no registered clients, not taking any further action.");
    }

,

BaseIntegrationGateway.createAndSendToSubscribers(65) | Inbound service message [news.create] to be sent to 3 registered clients: [Id=126, Service=IntegrationService.MESSAGE_NEWS, Client=MDC, Id=125, Service=IntegrationService.MESSAGE_NEWS, Client=CNBC, Id=125, Service=IntegrationService.MESSAGE_NEWS, Client=CNBC]
+3
2

java.concurrent.ConcurrentHashMap?

: , :

fillCachedIntegrationClients() :

for (IntegrationClient integrationClient : allCachedIntegrationClients) {
        putOneIntegrationClientOnCache(integrationClient);
    }

putOneIntegrationClientOnCache fillCachedIntegrationClients();

synchronized private void putOneIntegrationClientOnCache(IntegrationClient integrationClient){
fillCachedIntegrationClients(); // only fill cache if it is null , it will never refill cache
...

}

- . fillCachedIntegrationClients(). , , , . != Null . , undefined, , , .

+2

Undefined , - . , WWIII, , ..

- .

+3

Source: https://habr.com/ru/post/1781799/


All Articles