Bloqueio duplo verificado com ConcurrentMap
Tenho um pedaço de código que pode ser executado por vários encadeamentos que precisam executar uma operação vinculada a E / S para inicializar um recurso compartilhado armazenado em umConcurrentMap
. Preciso tornar esse segmento de código seguro e evitar chamadas desnecessárias para inicializar o recurso compartilhado. Aqui está o código do buggy:
private ConcurrentMap<String, Resource> map;
// .....
String key = "somekey";
Resource resource;
if (map.containsKey(key)) {
resource = map.get(key);
} else {
resource = getResource(key); // I/O-bound, expensive operation
map.put(key, resource);
}
Com o código acima, vários threads podem verificar oConcurrentMap
e veja se o recurso não existe e todas as tentativas de chamargetResource()
que é caro. Para garantir apenas uma única inicialização do recurso compartilhado e tornar o código eficiente depois que o recurso foi inicializado, desejo fazer algo assim:
String key = "somekey";
Resource resource;
if (!map.containsKey(key)) {
synchronized (map) {
if (!map.containsKey(key)) {
resource = getResource(key);
map.put(key, resource);
}
}
}
Esta é uma versão segura do bloqueio com verificação dupla? Parece-me que, uma vez que os cheques são chamadosConcurrentMap
, ele se comporta como um recurso compartilhado declarado comovolatile
e, assim, evita qualquer um dos problemas de "inicialização parcial" que possam ocorre