【Preguntas de la entrevista】 Entrevista HashMap 21 preguntas

Inserte la descripción de la imagen aquí

1. Información general

Reimpreso: http://www.javastack.cn/article/2020/hashmap-21-questions/

21 preguntas complicadas de la entrevista HashMap, ¡esta vez me arrodillaré!

1: ¿Estructura de datos de HashMap?

R: Se implementa la estructura de la tabla hash (hash de lista vinculada: matriz + lista vinculada), combinando las ventajas de las matrices y las listas vinculadas. Cuando la longitud de la lista vinculada excede 8, la lista vinculada se convierte en un árbol rojo-negro.

transient Node<K,V>\[\] table;

2: ¿Cómo funciona HashMap?

La capa inferior de HashMap es una matriz hash y una lista enlazada individualmente. Cada elemento de la matriz es una lista enlazada, que es implementada por la clase interna Node (implementando la interfaz Map.Entry <K, V>). HashMap se almacena y recupera a través del método put & get.

Al almacenar un objeto, pase el valor de la clave K / V al método put ():

① Llame al método hash (K) para calcular el valor hash de K, y luego combine la longitud de la matriz para calcular el subíndice de la matriz;

②. Ajustar el tamaño de la matriz (cuando el número de elementos en el contenedor es mayor que la capacidad * factor de carga, el contenedor se expandirá y cambiará de tamaño a 2n);

③, i. Si el valor hash de K no existe en el HashMap, se realiza la inserción, y si existe, ocurre una colisión;

ii. Si el valor hash de K existe en HashMap, y ambos devuelven verdaderos iguales, actualice el par clave-valor;

iii. Si el valor hash de K existe en el HashMap, y ambos devuelven falsos iguales, se inserta al final de la lista vinculada (interpolación de cola) o en el árbol rojo-negro (la forma en que se agrega el árbol). (La interpolación de cabeza se usó antes de JDK 1.7, y la interpolación de cola se usó en JDK 1.8) (Nota: Cuando la colisión hace que la lista vinculada sea más grande que TREEIFY_THRESHOLD = 8, la lista vinculada se convierte en un árbol rojo-negro)

Al obtener un objeto, pase K al método get (): ①, llame al método hash (K) (calcule el valor hash de K) para obtener el subíndice de matriz de la lista vinculada donde se encuentra el valor clave; ②, recorra la lista vinculada secuencialmente, método equals () Busque el valor de V correspondiente al valor de K en la misma lista enlazada de nodo.

HashCode se encuentra y almacena; equals es cualitativo y compara si los dos son iguales.

3. ¿Qué sucede cuando el código hash de dos objetos es el mismo?

Debido a que hashCode es el mismo, no es necesariamente igual (es igual a la comparación de métodos), por lo que los subíndices de la matriz donde se encuentran los dos objetos son los mismos y se produce la "colisión". Y debido a que HashMap usa una lista vinculada para almacenar objetos, este nodo se almacenará en la lista vinculada. ¿Por qué reescribir el código hash y los métodos iguales? Recomiendo echar un vistazo.

4. ¿Conoce la implementación del hash? ¿Por qué quieres lograr esto?

En JDK 1.8, se realiza mediante el alto XOR de 16 bits de hashCode (): (h = k.hashCode ()) ^ (h >>> 16), que se considera principalmente desde la perspectiva de la velocidad, la eficiencia y la calidad Reducirá la sobrecarga del sistema y no causará colisiones causadas por los bits altos que no participan en el cálculo del subíndice.

5. ¿Por qué utilizar el operador XOR?

Se garantiza que siempre que cambie un bit del valor de 32 bits del hashCode del objeto, cambiará todo el valor de retorno del hash (). Reduzca las colisiones tanto como sea posible.

6. ¿Cómo determinar la capacidad de la tabla HashMap? ¿Qué es loadFactor? ¿Cómo cambia esta capacidad? ¿Qué problemas traerá este cambio?

①. El tamaño de la matriz de la tabla está determinado por el parámetro de capacidad, el valor predeterminado es 16, o se puede pasar durante la construcción, el límite máximo es 1 << 30;

②, loadFactor es el factor de carga, el propósito principal es confirmar si la matriz de la tabla debe expandirse dinámicamente. El valor predeterminado es 0,75. Por ejemplo, cuando el tamaño de la matriz de la tabla es 16 y el factor de carga es 0,75, el umbral es 12 y cuando el tamaño real de la tabla excede 12 , La mesa necesita expansión dinámica;

③. Al expandir, llame al método resize () para duplicar la longitud de la tabla (tenga en cuenta que la longitud de la tabla, no el umbral)

④. Si los datos son grandes, se producirá una pérdida de rendimiento durante la expansión. En lugares con requisitos de alto rendimiento, esta pérdida puede ser fatal.

Recomendación: ¿Por qué la capacidad de HashMap es siempre una potencia de 2?

7. ¿Cuál es el proceso de poner el método en HashMap?

Respuesta: "Llame a la función hash para obtener el valor hash correspondiente a la clave, y luego calcule el subíndice de la matriz;

Si no hay conflicto de hash, colóquelo directamente en la matriz; si hay un conflicto de hash, colóquelo detrás de la lista vinculada en forma de lista vinculada;

Si la longitud de la lista vinculada excede el umbral (TREEIFY THRESHOLD == 8), la lista vinculada se convierte en un árbol rojo-negro y la lista vinculada es menor que 6, el árbol rojo-negro se convierte de nuevo a la lista vinculada;

Si la clave del nodo ya existe, simplemente reemplace su valor;

Si los pares clave-valor de la colección son mayores que 12, llame al método resize para expandir la matriz. "

8. ¿Cuál es el proceso de expansión de la matriz?

Cree una nueva matriz con el doble de capacidad que la matriz anterior y vuelva a calcular la ubicación de almacenamiento de los nodos en la matriz anterior. Solo hay dos posiciones de nodos en la nueva matriz, la posición del subíndice original o el subíndice original + el tamaño de la matriz anterior.

9. El problema de la lista de enlaces demasiado profundos causado por el método de cremallera, ¿por qué no utilizar el árbol de búsqueda binaria en lugar del árbol rojo-negro? ¿Por qué no utilizar siempre árboles rojo-negros?

La razón para elegir el árbol rojo-negro es resolver los defectos del árbol de búsqueda binaria. En circunstancias especiales, el árbol de búsqueda binaria se convertirá en una estructura lineal (esta es la misma que la estructura de lista vinculada original, lo que causa un problema profundo), búsqueda transversal Será muy lento. Recomendación: Le pregunté al árbol rojo-negro durante la entrevista, mi cara se puso verde.

Es posible que el árbol rojo-negro deba ser para zurdos, diestros y operaciones de cambio de color para mantener el equilibrio después de insertar nuevos datos. El árbol rojo-negro se introduce para encontrar datos rápidamente y resolver el problema de la profundidad de consulta de la lista vinculada. Sabemos que el árbol rojo-negro es un árbol binario equilibrado. Pero para mantener el "equilibrio", hay un precio que pagar, pero el costo de los recursos es menor que atravesar la lista vinculada lineal, por lo que cuando la longitud es mayor que 8, se usará el árbol rojo-negro, si la longitud de la lista vinculada es muy corta, no lo es en absoluto Necesita introducir árboles rojo-negros, pero la introducción será lenta.

10. ¿Cuéntame tu opinión sobre el árbol rojo-negro?

Cada nodo es rojo o negro

El nodo raíz siempre es negro

Si el nodo es rojo, sus nodos secundarios deben ser negros (no necesariamente al revés)

Cada nodo hoja es un nodo vacío negro (nodo NIL)

Cada ruta desde el nodo raíz hasta el nodo hoja o el nodo hijo vacío debe contener el mismo número de nodos negros (es decir, la misma altura negra)

11. ¿Qué cambios se han realizado en HashMap en jdk8?

En Java 1.8, si la longitud de la lista enlazada excede 8, entonces la lista enlazada se convertirá en un árbol rojo-negro. (La cantidad de depósitos debe ser mayor que 64. Si es menor que 64, solo se expandirá). Siga la cuenta oficial de WeChat: pila de tecnología Java y responda en segundo plano: Nuevas funciones. Puede obtener los tutoriales de nuevas funciones de N Java que he compilado, todos los cuales son productos secos.

Cuando se produce una colisión de hash, java 1.7 se insertará al principio de la lista vinculada y java 1.8 se insertará al final de la lista vinculada

En Java 1.8, Entry fue reemplazado por Node (cambio de chaleco).

12. ¿Cuál es la diferencia entre HashMap, LinkedHashMap y TreeMap?

HashMap se refiere a otras preguntas; preste atención a la cuenta pública de WeChat: pila de tecnología Java, responda en segundo plano: Java, puede obtener los tutoriales de la colección N Java que he compilado, todos los cuales son productos secos.

LinkedHashMap guarda el orden de inserción de los registros. Al atravesar con Iterator, el primer registro obtenido debe insertarse primero, el recorrido es más lento que HashMap;

TreeMap implementa la interfaz SortMap, que puede ordenar los registros que guarda de acuerdo con la clave (el valor de clave predeterminado está en orden ascendente y también se puede especificar el comparador de clasificación)

13. ¿Cuáles son los escenarios de uso de HashMap, TreeMap y LinkedHashMap?

En general, el más utilizado es HashMap.

HashMap: al insertar, eliminar y posicionar elementos en el mapa;

TreeMap: en el caso de que las claves deban recorrerse en orden natural o personalizado;

LinkedHashMap: en el caso de que el orden de salida y el orden de entrada sean los mismos.

14. ¿Cuál es la diferencia entre HashMap y HashTable?

①, HashMap no es seguro para subprocesos, HashTable es seguro para subprocesos;

② Debido a la seguridad de los subprocesos, la eficiencia de HashTable no es tan eficiente como HashMap;

③, HashMap solo permite que la clave de un registro sea nula y permite que el valor de varios registros sea nulo, pero HashTable no lo permite;

④, el tamaño de matriz de inicialización predeterminado de HashMap es 16, HashTable es 11. Cuando el primero se expande, se expande dos veces, el segundo se expande dos veces + 1;

⑤, HashMap necesita recalcular el valor hash, mientras que HashTable usa directamente el hashCode del objeto

15. ¿Cuál es otra clase segura para subprocesos en Java que es muy similar a HashMap? También es seguro para subprocesos. ¿Cuál es la diferencia entre él y HashTable en términos de sincronización de subprocesos?

Clase ConcurrentHashMap (una implementación de HashMap eficiente y segura para subprocesos proporcionada en el paquete de concurrencia de Java java.util.concurrent).

HashTable es el principio de utilizar la palabra clave sincronizar para bloquear (es decir, bloquear el objeto);

Para ConcurrentHashMap, el bloqueo segmentado se adopta en JDK 1.7; CAS (algoritmo sin bloqueo) + sincronizado se adopta directamente en JDK 1.8.

16. ¿Cuál es la diferencia entre HashMap y ConcurrentHashMap?

Excepto por el bloqueo, en principio no hay mucha diferencia. Además, el par clave-valor de HashMap permite null, pero ConCurrentHashMap no lo permite.

17. ¿Por qué ConcurrentHashMap es más eficiente que HashTable?

HashTable utiliza un bloqueo (que bloquea toda la estructura de la lista vinculada) para manejar los problemas de concurrencia. Varios subprocesos compiten por un bloqueo, que es fácil de bloquear;

ConcurrentHashMap

En JDK 1.7, se usa el bloqueo segmentado (ReentrantLock + Segment + HashEntry), que equivale a dividir un HashMap en varios segmentos y asignar un bloqueo a cada segmento, que admite el acceso multiproceso. Granularidad de bloqueo: basado en Segmento, contiene múltiples HashEntry.

CAS + sincronizado + Nodo + árbol rojo-negro se utiliza en JDK 1.8. Granularidad de bloqueo: Nodo (primer nodo) (implementa Map.Entry <K, V>). Se reduce la granularidad de la cerradura.

18. ¿Análisis específico para el mecanismo de bloqueo ConcurrentHashMap (JDK 1.7 VS JDK 1.8)?

En JDK 1.7, se usa un mecanismo de bloqueo segmentado para implementar operaciones de actualización concurrentes. La capa inferior usa una matriz + estructura de almacenamiento de lista vinculada, que incluye dos clases internas estáticas principales, Segment y HashEntry.

① El segmento hereda ReentrantLock (bloqueo reentrante) para actuar como un bloqueo. Cada objeto de segmento protege varios depósitos de cada mapa hash;

②, HashEntry se usa para encapsular los pares clave-valor de la tabla de mapeo;

③, cada depósito es una lista vinculada vinculada por varios objetos HashEntry

Inserte la descripción de la imagen aquí

En JDK 1.8, Node + CAS + Synchronized se utiliza para garantizar la seguridad de la concurrencia. Cancele la clase Segmento y use directamente la matriz de la tabla para almacenar pares clave-valor; cuando la longitud de la lista vinculada compuesta por objetos HashEntry excede TREEIFY_THRESHOLD, la lista vinculada se convierte en un árbol rojo-negro para mejorar el rendimiento. La capa inferior se cambia a matriz + lista vinculada + árbol rojo-negro.

Inserte la descripción de la imagen aquí

19. ConcurrentHashMap en JDK 1.8, ¿por qué utilizar el bloqueo integrado sincronizado en lugar del bloqueo reentrante ReentrantLock?

① El tamaño de las partículas se reduce;

② El equipo de desarrollo de JVM no ha renunciado a la sincronización, y el espacio de optimización para la optimización sincronizada basada en JVM es más grande y más natural.

③ Bajo la gran cantidad de operación de datos, debido a la presión de memoria de JVM, ReentrantLock basado en API gastará más memoria.

20. ¿Una breve introducción a ConcurrentHashMap?

① Constantes importantes:

privado transitorio volátil int sizeCtl;

Cuando es un número negativo, -1 significa inicializando, -N significa N-1 subprocesos se están expandiendo;

Cuando es 0, significa que la tabla no se ha inicializado;

Cuando es otro número positivo, indica el tamaño de inicialización o siguiente expansión.

② Estructura de datos:

El nodo es la unidad básica de la estructura de almacenamiento, hereda la entrada en HashMap, que se utiliza para almacenar datos;

TreeNode hereda Node, pero la estructura de datos se reemplaza por una estructura de árbol binario, que es la estructura de almacenamiento del árbol rojo-negro y se utiliza para almacenar datos en el árbol rojo-negro;

TreeBin es un contenedor que encapsula TreeNode y proporciona algunas condiciones y control de bloqueo para convertir árboles rojo-negro.

③ Al almacenar objetos (método put ()):

Si no está inicializado, llame al método initTable () para inicializar;

Si no hay conflicto de hash, inserción directa sin bloqueo CAS;

Si necesita ampliar la capacidad, amplíe la capacidad primero;

Si hay un conflicto de hash, se agregan bloqueos para garantizar la seguridad del hilo. Hay dos casos: uno es que la lista vinculada se recorre directamente hasta el final y se inserta, el otro es que el árbol rojo-negro se inserta de acuerdo con la estructura del árbol rojo-negro;

Si el número de la lista enlazada es mayor que el umbral 8, primero se debe convertir en una estructura de árbol rojo-negro, y break ingresa al ciclo nuevamente

Si la adición tiene éxito, llame al método addCount () para contar el tamaño y verificar si necesita expansión.

④ Transferencia del método de expansión (): la capacidad predeterminada es 16, cuando se expande, la capacidad se convierte en el doble de la original.

helpTransfer (): llame a varios subprocesos de trabajo juntos para ayudar a expandir la capacidad, por lo que la eficiencia será mayor.

⑤ Al obtener un objeto (método get ()):

Calcule el valor hash, ubique la posición del índice de la tabla y regrese si el primer nodo coincide;

Si encuentra expansión, llamará al método ForwardingNode.find () del nodo que marca el nodo de expansión, buscará el nodo y regresará si coincide;

Si ninguna de las coincidencias anteriores, recorre el nodo hacia abajo y regresa si la coincidencia coincide; de ​​lo contrario, devolverá un valor nulo al final.

21. ¿Cuál es la concurrencia de ConcurrentHashMap?

El número máximo de subprocesos que pueden actualizar ConccurentHashMap al mismo tiempo mientras el programa se ejecuta sin bloqueo de contención. El valor predeterminado es 16 y se puede configurar en el constructor.

Cuando el usuario establece la concurrencia, ConcurrentHashMap utilizará la potencia más pequeña de 2 exponentes mayor o igual que este valor como la concurrencia real (si el usuario establece la concurrencia en 17, la concurrencia real es 32)

Supongo que te gusta

Origin blog.csdn.net/qq_21383435/article/details/108465919
Recomendado
Clasificación