A semana de revisão começou, e o resumo sobre a coleção está aqui

1. Coleção

1 、 Lista 、 Conjunto 、 HashMap

Conte-me sobre a diferença entre os três?

Os elementos armazenados na lista são ordenados e repetíveis

Os elementos armazenados em Set são desordenados e não podem ser repetidos, e os elementos não podem estar vazios

Os elementos de armazenamento HashMap são armazenados na forma de pares chave-valor de chave-valor, a chave e o valor podem estar vazios

Quais são as classes de implementação abaixo deles?

Deixe-me falar sobre List primeiro. As seguintes classes de implementação incluem:

  • ArrayList: sua estrutura de dados subjacente é uma matriz e não é thread-safe. Seu mecanismo de expansão: expanda para 1,5 vezes o tamanho original, declare uma posição de 1,5 vez o espaço e copie o conteúdo da matriz original para este espaço maior
  • LinkedList: sua estrutura de dados subjacente é uma lista duplamente vinculada e não é segura para threads.
  • vetor: sua estrutura de dados subjacente é uma matriz, mas é thread-safe

Vamos falar sobre Set novamente. As seguintes classes de implementação incluem:

  • HashSet: ele herda o HashMap na camada inferior e seus elementos são armazenados na chave do HashMap na camada inferior, razão pela qual seu valor não deve ser repetitivo e é sobrescrito quando encontra um valor duplicado.
  • LinkedHashSet: LinkedHashSet é uma subclasse de HashSet, e a camada inferior é implementada por meio de LinkedHashMap.
  • TreeSet: árvore vermelho-preto (uma árvore binária de classificação auto-balanceada).

Por fim, vamos falar sobre Map. As seguintes classes de implementação incluem:

  • HashMap: na verdade, é uma tabela de hash. Antes de jdk1.8, a camada inferior usa uma matriz mais uma lista vinculada para armazenar elementos. Matrizes são o tema do HashMap. Listas vinculadas existem mais para resolver conflitos de hash (usando o método zipper para resolver conflitos de hash) ), em jdk1.8, a camada inferior é para armazenar elementos na forma de uma matriz mais uma lista vinculada e uma árvore vermelho-preto. A razão para introduzir a árvore vermelho-preto é evitar que a lista vinculada seja muito longa e reduzir a eficiência de recuperação.
  • TreeMap: árvore vermelha e preta, uma espécie de árvore binária de auto-equilíbrio
  • LinkedHashMap: LinkedHashMap herda de HashMap, então sua camada inferior ainda é uma matriz e uma estrutura de lista vinculada com base em uma tabela de hash zipper. A diferença é que ele adiciona uma lista duplamente vinculada com base no descrito acima. Esta lista duplamente vinculada mantém principalmente a ordem de inserção dos elementos .
  • HashTable: herda a classe Dictionary, que é composta por uma matriz e uma lista vinculada. HashTable não é segura para threads

Então me fale sobre o HashMap, certo?

Em 8, essa tabela hash tem uma nova estrutura de árvore vermelho-preto. Quando o comprimento da lista vinculada for maior que 8, ela será convertida em uma árvore vermelho-preto para melhorar a eficiência da consulta de elementos. Tem quatro construtores, incluindo um construtor sem parâmetro, um construtor que especifica a capacidade inicial, um construtor que especifica a capacidade inicial e o fator de carga e um construtor que envolve o Mapa. ​​Na verdade, ao especificar a capacidade inicial, você não especifica quanta capacidade é. , Ele inserirá um método tableForSize após o processamento para retornar uma potência de 2 mais próxima de si mesmo que é maior do que a capacidade especificada atual como a capacidade inicial de todo o HashMap. O mais importante é que os métodos put e get também têm um método resize. Antes de falar sobre esses métodos, mencionarei outra função, que é o método hash. A operação AND é feita principalmente aqui. O valor do hashcode da chave de HashMap é alto. O valor obtido pela operação AND dos 16 bits e dos 16 bits inferiores é retornado, e é usado como o valor do atributo hash no objeto Node. Volte para o método get, calcule seu valor de hash passando a chave e, em seguida, calcule o índice de acordo com o comprimento da matriz Node, encontre o hash da chave do elemento head da matriz correspondente a este índice e se o objeto é consistente com a chave passada, se for consistente , Retorne este elemento e julgue se for inconsistente Se o elemento principal tem o próximo nó, se houver um nó, atravesse para baixo. De acordo com as diferentes instâncias do nó principal, diferentes métodos de passagem são usados. valor. Vamos falar sobre o método put. É um método de inserção de elementos. Ele também calcula o índice subscrito com base no valor de hash e no comprimento da matriz, encontra este subscrito e o insere diretamente se não houver valor. Se houver um valor, avalia o elemento principal Se a chave for igual à chave do elemento a ser inserido, se forem iguais, substitua diretamente o elemento. Se forem diferentes, julgue a instância deste elemento. Se for uma instância de árvore, insira o elemento de acordo com o método de inserção de instância de árvore. Se for uma lista vinculada, apenas Percorra a lista encadeada, e se for determinado que existe um elemento consistente com este elemento no caminho, o valor é sobrescrito, caso contrário, o elemento a ser inserido é inserido no final da lista encadeada. Vamos falar sobre o método de expansão de redimensionamento.Este método não é usado apenas para expansão, mas também para inicializar capacidade. Quando a capacidade é inicializada, os valores padrão são anexados ao Wing Wolf e ao fator de carga. Ao expandir a capacidade, analisamos seu código-fonte e descobrimos que ele não re-hash, mas usamos o valor de hash original para julgar se um de seus bits era 0 ou 1 e, se fosse 0, colocamos na lista vinculada de ordem inferior, que é 1. Coloque-o na lista alta. Após a conclusão da travessia, a lista vinculada de ordem superior é colocada no índice de ordem superior da nova matriz e a lista vinculada de ordem inferior é colocada no índice inferior da nova matriz. Finalmente, a expansão de HashMap é diferente entre jdk1.7 e 1.8. 1.7 usa o método de inserção de cabeçote, 1.8 usa o método de inserção de cauda e o método de inserção de cabeçote 1.7 pode causar um loop infinito na lista vinculada ao expandir. 1.8 O cenário de insegurança do thread se reflete na possibilidade de perda do elemento ao inserir elementos.

Quais coleções são thread-safe? O que não é seguro e como resolver?

Nossos ArrayList, LinkedList, HashSet, HashMap, etc. comumente usados ​​não são seguros para thread. Você pode substituí-los por coleções seguras para thread ou pode usar métodos sob a classe de ferramenta Collections para envolver essas coleções para garantir a segurança do thread. Mas estes são modificados por synchronized, o desempenho ficará muito menor.

Além disso, existem muitos contêineres no pacote JUC, incluindo ConcurrentHashMap, CopyOnWriteArrayList, etc. ConcurrentHashMap pode ser considerado um HashMap seguro para thread e CopyOnWriteArrayList pode ser considerado um ArrayList seguro para thread. Seu desempenho é muito superior ao de um vetor e é adequado para ocasiões com mais leitura e menos escrita.

Você mencionou ConcurrentHashMap antes, pode falar sobre isso?

A camada inferior do ConcurrentHashMap é uma estrutura de array + lista vinculada + árvore vermelha e preta.É thread-safe e sua segurança de thread é realizada por bloqueio segmentado antes de jdk1.8. Ler sem bloqueio, escrever com bloqueio, mantém uma matriz de segmento internamente e bloqueia os dados em um determinado índice desta matriz. Em vez de bloquear toda a tabela de hash, isso é muito melhor do que o desempenho do HashTable. Foi alterado em jdk1.8, o segmento foi removido e otimizado, e o nó principal foi bloqueado por rotação sincronizada + CAS para tornar o bloqueio mais Refinado e melhorar ainda mais o desempenho.

A propósito, fale também sobre CopyOnWriteArrayList

Ele mantém um ReentrantLock na parte inferior para garantir a segurança do thread exibindo bloqueios e desbloqueios ao inserir elementos.

2. O que é falha rápida e falha segura

Falha rápida: é um mecanismo de detecção de erros de coleções Java. Quando somos iteradores percorrendo a coleção, podemos acionar a falha rápida ao operar essas coleções que falham com segurança em multithreading, lançando ** ConcurrentModificationException** exceções.

Falha de segurança: esta exceção não será lançada no cenário acima.

Acho que você gosta

Origin blog.csdn.net/MarkusZhang/article/details/107918808
Recomendado
Clasificación