Eu tenho um mapa que deve ser modificado por vários segmentos simultaneamente.
Parece haver três implementações diferentes de mapas sincronizados na API Java:
Hashtable
Collections.synchronizedMap(Map)
ConcurrentHashMap
Pelo que entendi, Hashtable
é uma implementação antiga (estendendo a Dictionary
classe obsoleta ), que foi adaptada posteriormente para se ajustar à Map
interface. Embora esteja sincronizado, parece ter sérios problemas de escalabilidade e é desencorajado para novos projetos.
Mas e os outros dois? Quais são as diferenças entre mapas devolvidos por Collections.synchronizedMap(Map)
e ConcurrentHashMap
s? Qual deles se encaixa em qual situação?
java
dictionary
concurrency
Henning
fonte
fonte
ConcurrentSkipListMap
como outraMap
implementação segura para threads . Projetado para ser altamente simultâneo sob carga, usando o algoritmo Skip List .Respostas:
Para suas necessidades, use
ConcurrentHashMap
. Permite a modificação simultânea do mapa a partir de vários threads, sem a necessidade de bloqueá-los.Collections.synchronizedMap(map)
cria um mapa de bloqueio que prejudicará o desempenho, embora garanta consistência (se usado corretamente).Use a segunda opção se precisar garantir a consistência dos dados, e cada encadeamento precisa ter uma visualização atualizada do mapa. Use o primeiro se o desempenho for crítico e cada thread inserir apenas dados no mapa, com leituras acontecendo com menos frequência.
fonte
Em relação ao mecanismo de bloqueio:
Hashtable
bloqueia o objeto , enquantoConcurrentHashMap
bloqueia apenas o balde .fonte
Hashtable
não está bloqueando parte do mapa. Veja a implementação. Ele está usando umasynchronized
chave sem trava fornecida, o que significa basicamente que ela trava inteirahashtable
em cada operação.Os "problemas de escalabilidade" de
Hashtable
estão presentes exatamente da mesma maneiraCollections.synchronizedMap(Map)
- eles usam sincronização muito simples, o que significa que apenas um encadeamento pode acessar o mapa ao mesmo tempo.Isso não é muito problemático quando você tem inserções e pesquisas simples (a menos que você faça isso intensivamente), mas se torna um grande problema quando você precisa percorrer todo o mapa, o que pode levar muito tempo para um mapa grande - enquanto um thread faz isso, todos os outros precisam esperar se quiserem inserir ou procurar alguma coisa.
Ele
ConcurrentHashMap
usa técnicas muito sofisticadas para reduzir a necessidade de sincronização e permitir acesso de leitura paralelo por vários threads sem sincronização e, mais importante, fornece umIterator
que não requer sincronização e até permite que o Mapa seja modificado durante a interação (embora não garanta se nenhum elemento que foi inserido durante a iteração será retornado).fonte
O ConcurrentHashMap é preferido quando você pode usá-lo - embora exija pelo menos o Java 5.
Ele foi projetado para dimensionar bem quando usado por vários threads. O desempenho pode ser marginalmente pior quando apenas um único encadeamento acessa o mapa por vez, mas significativamente melhor quando vários encadeamentos acessam o mapa simultaneamente.
Encontrei uma entrada de blog que reproduz uma tabela do excelente livro Java Concurrency In Practice , que eu recomendo completamente.
Collections.synchronizedMap realmente só faz sentido se você precisar agrupar um mapa com algumas outras características, talvez algum tipo de mapa ordenado, como um TreeMap.
fonte
A principal diferença entre esses dois é que
ConcurrentHashMap
bloqueará apenas parte dos dados que estão sendo atualizados, enquanto outras partes dos dados podem ser acessadas por outros threads. No entanto,Collections.synchronizedMap()
todos os dados serão bloqueados durante a atualização; outros segmentos só poderão acessar os dados quando o bloqueio for liberado. Se houver muitas operações de atualização e uma quantidade relativamente pequena de operações de leitura, você deverá escolherConcurrentHashMap
.Outra diferença é que
ConcurrentHashMap
não preservará a ordem dos elementos no mapa transmitido. É semelhante aoHashMap
armazenamento de dados. Não há garantia de que a ordem dos elementos seja preservada. EnquantoCollections.synchronizedMap()
preservará a ordem dos elementos do mapa transmitido. Por exemplo, se você passar umTreeMap
paraConcurrentHashMap
, a ordem dos elementos noConcurrentHashMap
pode não ser a mesma que a ordem noTreeMap
, masCollections.synchronizedMap()
preservará a ordem.Além disso,
ConcurrentHashMap
pode garantir que não hajaConcurrentModificationException
lançamentos enquanto um thread estiver atualizando o mapa e outro thread estiver percorrendo o iterador obtido no mapa. No entanto,Collections.synchronizedMap()
não é garantido isso.Há um post que demonstra as diferenças desses dois e também o
ConcurrentSkipListMap
.fonte
Mapa sincronizado:
O Mapa Sincronizado também não é muito diferente do Hashtable e fornece desempenho semelhante em programas Java simultâneos. A única diferença entre Hashtable e SynchronizedMap é que SynchronizedMap não é um legado e você pode agrupar qualquer mapa para criar sua versão sincronizada usando o método Collections.synchronizedMap ().
ConcurrentHashMap:
A classe ConcurrentHashMap fornece uma versão simultânea do HashMap padrão. Este é um aprimoramento da funcionalidade synchronizedMap fornecida na classe Collections.
Ao contrário do Hashtable e do mapa sincronizado, ele nunca bloqueia o mapa inteiro; em vez disso, divide o mapa em segmentos e o bloqueio é feito nesses. Ele tem um desempenho melhor se o número de threads do leitor for maior que o número de threads do gravador.
ConcurrentHashMap, por padrão, é separado em 16 regiões e os bloqueios são aplicados. Esse número padrão pode ser definido ao inicializar uma instância ConcurrentHashMap. Ao definir dados em um segmento específico, a trava para esse segmento é obtida. Isso significa que duas atualizações ainda podem ser executadas simultaneamente com segurança se cada uma delas afetar depósitos separados, minimizando a contenção de bloqueios e maximizando o desempenho.
ConcurrentHashMap não lança uma ConcurrentModificationException
ConcurrentHashMap não lança uma ConcurrentModificationException se um thread tentar modificá-lo enquanto outro estiver iterando sobre ele
Diferença entre synchornizedMap e ConcurrentHashMap
Collections.synchornizedMap (HashMap) retornará uma coleção que é quase equivalente ao Hashtable, onde todas as operações de modificação no Map são bloqueadas no objeto Map enquanto no caso do ConcurrentHashMap, a segurança do thread é alcançada dividindo todo o Mapa em uma partição diferente, com base no nível de simultaneidade. e apenas bloquear parte específica em vez de bloquear todo o mapa.
ConcurrentHashMap não permite chaves nulas ou valores nulos, enquanto o HashMap sincronizado permite uma chave nula.
Links semelhantes
Link1
Link2
Comparação de desempenho
fonte
Hashtable
eConcurrentHashMap
não permitanull
chaves ounull
valores.Collections.synchronizedMap(Map)
sincroniza todas as operações (get
,put
,size
, etc.).ConcurrentHashMap
suporta simultaneidade total de recuperações e simultaneidade esperada ajustável para atualizações.Como sempre, há tradeoffs de simultaneidade - sobrecarga - velocidade envolvidos. Você realmente precisa considerar os requisitos detalhados de simultaneidade do seu aplicativo para tomar uma decisão e, em seguida, testar seu código para ver se é bom o suficiente.
fonte
Em
ConcurrentHashMap
, o bloqueio é aplicado a um segmento em vez de a um mapa inteiro. Cada segmento gerencia sua própria tabela de hash interna. O bloqueio é aplicado apenas para operações de atualização.Collections.synchronizedMap(Map)
sincroniza o mapa inteiro.fonte
Você está certo
HashTable
, você pode esquecê-lo.Seu artigo menciona o fato de que, enquanto o HashTable e a classe de wrapper sincronizado fornecem segurança básica de encadeamento, permitindo apenas um encadeamento por vez acessar o mapa, isso não é uma segurança de encadeamento 'verdadeira', pois muitas operações compostas ainda exigem sincronização adicional, por exemplo:
No entanto, não pense que
ConcurrentHashMap
é uma alternativa simples para um blocoHashMap
típicosynchronized
, como mostrado acima. Leia este artigo para entender melhor seus meandros.fonte
Aqui estão alguns:
1) ConcurrentHashMap bloqueia apenas parte do mapa, mas SynchronizedMap bloqueia o MAp inteiro.
2) ConcurrentHashMap tem melhor desempenho em relação ao SynchronizedMap e é mais escalável.
3) No caso de vários leitores e gravadores individuais, o ConcurrentHashMap é a melhor opção.
Este texto é da Diferença entre ConcurrentHashMap e hashtable em Java
fonte
Podemos obter segurança de encadeamento usando ConcurrentHashMap e synchronisedHashmap e Hashtable. Mas há muita diferença se você olhar para a arquitetura deles.
fonte
ConcurrentHashMap
SynchronizedHashMap
fonte
fonte
ConcurrentHashMap é otimizado para acesso simultâneo.
Os acessos não bloqueiam o mapa inteiro, mas usam uma estratégia mais refinada, o que melhora a escalabilidade. Também há aprimoramentos funcionais especificamente para acesso simultâneo, por exemplo, iteradores simultâneos.
fonte
Há um recurso crítico a ser observado
ConcurrentHashMap
além do recurso de simultaneidade que ele fornece, que é o iterador à prova de falhas . Vi desenvolvedores usandoConcurrentHashMap
apenas porque desejam editar o conjunto de entradas - colocar / remover enquanto iteram sobre ele.Collections.synchronizedMap(Map)
não fornece um iterador à prova de falhas, mas sim um iterador à prova de falhas . Os iteradores fail-fast usam instantâneos do tamanho do mapa que não podem ser editados durante a iteração.fonte
fonte
Em geral, se você deseja usar o,
ConcurrentHashMap
verifique se está pronto para perder as 'atualizações'(ou seja, imprimir o conteúdo do HashMap não garante que ele imprima o Mapa atualizado) e use APIs como essa
CyclicBarrier
para garantir a consistência entre os programas. ciclo da vida.fonte
O método Collections.synchronizedMap () sincroniza todos os métodos do HashMap e o reduz efetivamente a uma estrutura de dados em que um thread pode entrar por vez, porque bloqueia todos os métodos em um bloqueio comum.
No ConcurrentHashMap, a sincronização é feita de maneira um pouco diferente. Em vez de bloquear todos os métodos em um bloqueio comum, o ConcurrentHashMap usa bloqueio separado para baldes separados, bloqueando apenas uma parte do Mapa. Por padrão, existem 16 baldes e também bloqueios separados para baldes separados. Portanto, o nível de simultaneidade padrão é 16. Isso significa que, teoricamente, a qualquer momento, 16 threads podem acessar o ConcurrentHashMap se todos eles estiverem indo para separar os buckets.
fonte
O ConcurrentHashMap foi apresentado como alternativa ao Hashtable no Java 1.5 como parte do pacote de simultaneidade. Com o ConcurrentHashMap, você tem uma opção melhor, não apenas se pode ser usado com segurança no ambiente multithread simultâneo, mas também oferece melhor desempenho do que o Hashtable e o synchronizedMap. ConcurrentHashMap tem melhor desempenho porque bloqueia uma parte do mapa. Ele permite operações de leitura simultâneas e, ao mesmo tempo, mantém a integridade, sincronizando as operações de gravação.
Como o ConcurrentHashMap é implementado
O ConcurrentHashMap foi desenvolvido como alternativa ao Hashtable e suporta todas as funcionalidades do Hashtable com capacidade adicional, o chamado nível de simultaneidade. ConcurrentHashMap permite que vários leitores leiam simultaneamente sem usar blocos. Torna-se possível separando o Mapa em partes diferentes e bloqueando apenas parte do Mapa nas atualizações. Por padrão, o nível de simultaneidade é 16, portanto, o Mapa é dividido em 16 partes e cada parte é gerenciada por bloco separado. Isso significa que 16 threads podem trabalhar com o Map simultaneamente, se trabalharem com diferentes partes do Map. Isso torna o ConcurrentHashMap altamente produtivo, e não diminui a segurança dos threads.
Se você está interessado em alguns recursos importantes do ConcurrentHashMap e quando deve usar essa realização do Map - apenas coloquei um link para um bom artigo - Como usar o ConcurrentHashMap em Java
fonte
Além do que foi sugerido, eu gostaria de postar o código fonte relacionado a
SynchronizedMap
.Para tornar um
Map
thread seguro, podemos usarCollections.synchronizedMap
instrução e inserir a instância do mapa como parâmetro.A implementação de
synchronizedMap
inCollections
é como abaixoComo você pode ver, o
Map
objeto de entrada é envolvido peloSynchronizedMap
objeto.Vamos nos aprofundar na implementação de
SynchronizedMap
,O que
SynchronizedMap
faz pode ser resumido como a adição de um único bloqueio ao método primário doMap
objeto de entrada . Todo o método protegido pelo bloqueio não pode ser acessado por vários threads ao mesmo tempo. Isso significa operações normais comoput
eget
pode ser executado por um único thread ao mesmo tempo para todos os dados noMap
objeto.Torna o
Map
thread do objeto seguro agora, mas o desempenho pode se tornar um problema em alguns cenários.Como
ConcurrentMap
é muito mais complicado na implementação, podemos consultar Construindo um HashMap melhor para obter detalhes. Em poucas palavras, é implementado levando em consideração o desempenho e a segurança do thread.fonte