Use ConcurrentHashMap. Ele trava por bin em vez do mapa inteiro, usando um compare and set para bins vazios e sincronizando na cabeça do bin nos outros casos, então leitores nunca bloqueiam e escritores em bins diferentes seguem em paralelo. Um mapa sincronizado serializa toda operação num único lock, e ainda exige sincronização externa durante a iteração. Use os métodos atômicos dele, como compute e merge, em vez de get seguido de put.
Por que os entrevistadores perguntam isso
Isso verifica se você sabe por que as coleções concorrentes existem em vez de apelar para synchronized por reflexo. O entrevistador quer a diferença de granularidade e o ponto prático crucial de que embrulhar um mapa não torna sequências de operações atômicas. Saber que size e iteração são fracamente consistentes, e quando CopyOnWriteArrayList ou uma BlockingQueue é a ferramenta melhor, arredonda a resposta.
Como estruturar sua resposta
- Cite a ferramenta primeiro, depois o mecanismo que a torna mais rápida.
- Explique por que um wrapper sincronizado ainda não basta para ações compostas.
- Aponte os métodos atômicos para ler, modificar e escrever.
- Cite as outras coleções concorrentes e quando elas se encaixam.
Exemplo de resposta
ConcurrentHashMap, quase sempre. A diferença importante é granularidade: ele trava no nível de um único bin, e uma inserção num bin vazio é só um compare and set, então chaves não relacionadas não competem e as leituras são livres de lock. Um mapa sincronizado coloca um lock em volta de tudo, então ele vira o gargalo assim que várias threads ficam ocupadas. A armadilha maior com um wrapper sincronizado é que chamadas individuais são atômicas mas sequências não são, então se eu checo containsKey e depois faço put, outra thread pode se enfiar entre as duas, e a iteração não é segura de jeito nenhum sem eu segurar o lock. É por isso que eu uso os métodos atômicos: computeIfAbsent para uma entrada de cache construída sob demanda, merge para contadores, para que o ler, modificar e escrever aconteça dentro do mapa. As coisas que dá para saber são que size é uma estimativa sob modificação concorrente e que os iteradores são fracamente consistentes, então eles não lançam mas podem não ver as escritas mais novas. Para outros formatos eu uso CopyOnWriteArrayList quando as leituras superam de longe as escritas, e uma BlockingQueue para repasse entre produtor e consumidor.
Vai encarar essa entrevista em breve? O GhostPilot escuta a sua chamada ao vivo, identifica a pergunta no instante em que ela é feita e coloca uma resposta estruturada na sua tela em tempo real. Teste na sua próxima entrevista simulada ou pegue um Session Pass de $29, sem assinatura, para a hora da verdade.
Veja como funcionaPerguntas de acompanhamento que você pode esperar
- Quais são os riscos de fazer trabalho caro dentro de computeIfAbsent?
- O que iteração fracamente consistente significa na prática?
- Quando CopyOnWriteArrayList é a escolha errada?
Mais perguntas para Desenvolvedor Java
Seu entrevistador vai fazer a própria versão desta. Cole a descrição real da vaga no Question Predictor gratuito e receba as 20 perguntas que essa vaga tem mais chance de fazer, com o que cada uma está de fato sondando.
Prever minhas perguntas