【JavaEE】Estrategia de bloqueo

Insertar descripción de la imagen aquí

Prefacio

En el subproceso múltiple anterior, aprendimos a usar sincronizado para bloquear subprocesos para resolver el problema de la inseguridad de los subprocesos. Sin embargo, como programador, no basta con saber cómo usar bloqueos, también necesita saber qué bloqueo. estrategias que hay. Hoy compartiré con ustedes qué estrategias de bloqueo existen en subprocesos múltiples.

1. Bloqueo optimista y bloqueo pesimista

El bloqueo pesimista es un mecanismo de bloqueo basado en una actitud pesimista, que asume el peor de los casos, es decir, bloqueará los datos antes de modificarlos, evitando que nadie pueda operar con los datos hasta que libere el bloqueo. Este mecanismo de bloqueo puede garantizar completamente la exclusividad y exactitud de los datos, porque cada solicitud primero bloqueará los datos, luego realizará operaciones con los datos y finalmente los desbloqueará. Sin embargo, el rendimiento de esta estrategia no es elevado debido al consumo que provoca el proceso de bloqueo y desbloqueo.

El bloqueo optimista es un mecanismo de bloqueo basado en el optimismo que supone que no ocurrirán conflictos de datos y solo bloquea los datos cuando se envía la operación. Esto significa que otros procesos pueden continuar operando sobre los datos antes de que se confirmen. El bloqueo optimista puede lograr operaciones paralelas y, por lo tanto, tiene un mayor rendimiento. Sin embargo, cabe señalar que si se produce un conflicto de datos, el sistema de base de datos debe gestionarlo.

Insertar descripción de la imagen aquí

Tanto el bloqueo optimista como el bloqueo pesimista son predicciones informáticas de lo que sucederá a continuación. El bloqueo pesimista pensará que el conflicto de bloqueo será grave más adelante, por lo que se bloqueará antes de modificar los datos, mientras que el bloqueo optimista pensará que el conflicto de bloqueo no será grave más adelante, por lo que no se bloqueará antes de procesar los datos.

Déjame darte un ejemplo simple: acabo de llegar a una ciudad, quiero jugar baloncesto en el gimnasio el fin de semana, pero como acabo de llegar no sé a qué hora abrirá el gimnasio. Entonces, en este momento, el método de bloqueo pesimista es: esperaré en casa ahora y les preguntaré a mis amigos cuándo abrirá el gimnasio, pero es posible que mis amigos todavía estén durmiendo, por lo que solo puedo esperar en casa; mientras que el método de bloqueo optimista es: "Ahora todo el mundo está abierto". Son las 8 en punto. El gimnasio debería abrir. Iré allí primero. Si se abre, puedo entrar directamente. Incluso si no es así, puedo esperar fuera del gimnasio durante un rato. mientras."

2. Cerraduras pesadas y cerraduras ligeras

Las cerraduras pesadas y las cerraduras livianas se dividen desde la perspectiva de la carga de trabajo.

Los bloqueos pesados ​​se implementan en función del bloqueo mutex del sistema operativo, lo que hará que el proceso cambie entre el modo de usuario y el modo kernel, lo cual es relativamente costoso. Por ejemplo, sincronizado se implementa internamente en función del bloqueo del monitor (monitor), que se implementa en función del bloqueo Mutex del sistema operativo subyacente, por lo que en este caso sincronizado es un bloqueo pesado y el bloqueo pesado debe estar entre el estado del usuario y el estado del núcleo.Convertir entre.

  • Una gran cantidad de cambios de modo de usuario en modo kernel
  • Es fácil provocar la programación de subprocesos.

Las cerraduras livianas se comparan con las cerraduras pesadas. El diseño central de las cerraduras livianas reduce el uso de cerraduras pesadas para mejorar el rendimiento del sistema sin competencia de subprocesos múltiples. Los candados livianos son adecuados para situaciones en las que los subprocesos ejecutan alternativamente bloques de código sincronizados (es decir, operaciones mutuamente excluyentes). Si varios subprocesos acceden al mismo candado al mismo tiempo, el candado liviano se expandirá y se convertirá en un candado pesado. Cuando ocurre competencia de subprocesos, los bloqueos livianos ceden los permisos de ejecución de la CPU para que otros subprocesos puedan continuar funcionando.

  • Una pequeña cantidad de cambio de modo de usuario en modo kernel.
  • Es menos probable que active la programación de subprocesos

¿Por qué la eficiencia de conversión entre el modo de usuario y el modo kernel de los bloqueos pesados ​​es menor?

La velocidad de lectura y escritura del modo de usuario es más lenta que la del modo kernel. En el estado del kernel, la CPU puede acceder a todos los datos de la memoria, incluidos dispositivos periféricos como discos duros, tarjetas de red, etc. Al mismo tiempo, la CPU también puede pasar de un programa a otro. En el modo de usuario, los programas sólo pueden tener acceso limitado a la memoria y no pueden acceder a dispositivos periféricos. En este caso, si un programa en modo de usuario necesita acceder a un dispositivo periférico, como un disco duro, primero debe cambiar al modo kernel y luego realizar llamadas al sistema desde el modo kernel para leer y escribir en el disco. causará gastos generales adicionales.

¿Por qué las operaciones en modo kernel son menos eficientes que las operaciones en modo usuario?

La implementación del modo kernel ocupará recursos escasos del kernel. Por ejemplo, el sistema operativo necesita mantener una lista de subprocesos, que no se puede cambiar dinámicamente una vez que se carga el sistema operativo. Y la cantidad de subprocesos es mucho mayor que la cantidad de procesos. A medida que aumenta la cantidad de subprocesos, los núcleos se agotará, lo que reducirá la eficiencia. Además, cada vez que un hilo cambia al modo kernel, debe ingresar al kernel y ser programado por el sistema operativo, lo que también llevará una cierta cantidad de tiempo.

3. Bloqueo de giro y bloqueo de espera pendiente

Un bloqueo giratorio es un bloqueo liviano . Cuando un subproceso no logra adquirir el bloqueo, seguirá intentando adquirirlo en un bucle hasta que lo logre. Este mecanismo consume muchos recursos de la CPU porque hace que el subproceso intente constantemente adquirir el bloqueo y no pueda realizar otro trabajo. El bloqueo de giro solo realiza una espera ocupada cuando el bloqueo falla y no bloquea el hilo.

//这是一个自旋锁的伪代码
//当getLocker的返回结果为false的时候,表示未获取到锁,那么就继续循环
while(getLocker == false) {
    
      
}

Los bloqueos de espera suspendidos son una implementación típica de bloqueos pesados . Cuando un hilo intenta adquirir un bloqueo y falla, se bloquea y espera a través del mecanismo del núcleo hasta que se libere el bloqueo. En este momento, el subproceso liberará recursos de la CPU para que otros subprocesos puedan ejecutarse. Cuando se libera el bloqueo, el hilo suspendido vuelve a intentar adquirir el bloqueo. Los bloqueos de espera suspendidos bloquearán el hilo durante la espera, evitando que el hilo realice otro trabajo.

//挂起等待锁,未获取到锁则是进入阻塞等待,等待内核态操作获取到锁
synchronized (locker) {
    
    
}

Aunque los bloqueos de giro consumen recursos de la CPU, dan como resultado tiempos de respuesta más rápidos.

La selección de estas dos cerraduras depende de los escenarios y requisitos de aplicación específicos. Si la interacción entre hilos es muy frecuente y el bloqueo se mantiene por un corto tiempo, un bloqueo de giro puede ser más adecuado. Si hay poca interacción entre subprocesos y el bloqueo se mantiene durante mucho tiempo, entonces puede ser más apropiado suspender y esperar el bloqueo.

Cuando un hilo quiere adquirir un bloqueo pero el bloqueo es adquirido por otro hilo, el bloqueo pendiente entrará en el estado de espera de bloqueo, porque el momento en que se despertará el hilo bloqueado es un factor incierto, que está determinado por las operaciones en modo kernel. la velocidad de ejecución del programa disminuirá, el bloqueo de giro no entrará en el estado de espera de bloqueo, pero realizará un ciclo continuo para determinar si el bloqueo todavía está ocupado. Si el bloqueo todavía está ocupado, el bloqueo de giro continuará en bucle hasta que se cierre el bloqueo. liberado Cuando se libera el bloqueo, el hilo puede adquirir el bloqueo, asegurando que toda la operación esté en modo de usuario.

4. Bloqueo justo y bloqueo injusto

Los bloqueos justos y los bloqueos injustos son dos mecanismos de sincronización de subprocesos comúnmente utilizados para proteger recursos compartidos en un entorno de subprocesos múltiples.

El bloqueo justo significa que varios subprocesos adquieren bloqueos en el orden en que los solicitan, es decir, por orden de llegada. En el bloqueo justo, si hay varios subprocesos esperando para adquirir el bloqueo, el bloqueo se asignará al subproceso con el tiempo de espera más largo en orden, lo que puede evitar la inanición del subproceso. La implementación del bloqueo justo es más complicada y requiere mantener una cola de espera de subprocesos, por lo que el rendimiento será relativamente bajo.

Un bloqueo injusto significa que varios subprocesos adquieren bloqueos en el orden en que compiten para adquirirlos, es decir, el principio de orden de llegada, no necesariamente primero en ser atendido. En los bloqueos injustos, si hay varios subprocesos esperando para adquirir el bloqueo, el bloqueo puede asignarse directamente al subproceso con un tiempo de espera más corto, lo que puede provocar que algunos subprocesos no puedan adquirir el bloqueo, lo que provoca la inanición del subproceso. La implementación del bloqueo injusto es relativamente simple y no es necesario mantener una cola de espera de subprocesos, por lo que el rendimiento será relativamente alto.

5. Cerraduras reentrantes y cerraduras no reentrantes

El bloqueo reentrante significa que cuando el mismo hilo adquiere el bloqueo en el método externo, el método interno que ingresa al hilo adquirirá automáticamente el bloqueo (siempre que el objeto del bloqueo deba ser el mismo objeto) y no será devuelto porque el bloqueo ya no existe. sido adquirido antes Bloqueado sin liberación. Una ventaja de los bloqueos reentrantes es que se pueden evitar los puntos muertos.

Los bloqueos no reentrantes son lo contrario: después de que un hilo adquiere el bloqueo, no puede adquirirlo internamente, ya que se adquirió antes y no se ha liberado, lo que puede provocar un punto muerto en el hilo.

6. Bloqueo de lectura y escritura

Nuestras operaciones habituales sobre datos son operaciones de lectura y operaciones de escritura. Si es un solo hilo, las operaciones de lectura y escritura no causarán problemas, pero si ocurre en varios hilos, habrá algunos problemas. Cuando un hilo está leyendo datos, otro hilo está escribiendo estos datos, entonces los datos leídos al final son diferentes de los datos en sí; cuando ambos hilos realizan operaciones de escritura, el resultado final no es el resultado correcto y varios hilos leen al mismo tiempo No habrá problemas durante la operación. En otras palabras, los problemas de seguridad de subprocesos no ocurrirán solo cuando varios subprocesos realicen operaciones de lectura al mismo tiempo, entonces, ¿cómo resolver los problemas de operaciones de lectura y escritura en subprocesos múltiples?

Bloqueo de lectura y escritura, cuando varios subprocesos realizan operaciones de lectura al mismo tiempo, no se producirán problemas de exclusión mutua.Si varios subprocesos realizan operaciones de lectura y escritura al mismo tiempo o operaciones de escritura al mismo tiempo, los bloqueos de lectura y escritura se realizan mutuamente. exclusivo Más tarde El hilo no puede adquirir este bloqueo.

Las características de los bloqueos de lectura-escritura son:

  1. La lectura no es mutuamente excluyente: varios subprocesos pueden leer recursos compartidos al mismo tiempo porque la operación de lectura en sí es segura para subprocesos.
  2. Exclusión mutua de lectura y escritura: cuando un subproceso escribe en un recurso compartido, otros subprocesos no pueden realizar operaciones de lectura o escritura porque las operaciones de lectura y escritura son mutuamente excluyentes para evitar la inconsistencia de los datos o la competencia de datos.
  3. Exclusión mutua de escritura y escritura: cuando dos o más subprocesos escriben en un recurso compartido al mismo tiempo, se producirá un fenómeno de exclusión mutua para evitar que los datos interfieran entre sí.

¿A qué estrategias de bloqueo corresponde Java sincronizado?

1. Bloqueo optimista y bloqueo pesimista

Para bloqueos optimistas y bloqueos pesimistas, sincronizado es un bloqueo adaptativo. Al principio, sincronizado es un bloqueo optimista, pero si la computadora predice que el conflicto de bloqueo será grave en el futuro, sincronizado se transformará en un bloqueo pesimista.

2. Cerraduras pesadas y cerraduras ligeras

Para cerraduras pesadas y ligeras, sincronizada también es una cerradura adaptativa. Al principio, debido a que la carga de trabajo del hilo es pequeña, sincronizado es un bloqueo liviano, pero si la carga de trabajo que el hilo necesita manejar más adelante es mayor, sincronizado se convertirá en un bloqueo pesado.

3. Bloqueo de giro y bloqueo de espera pendiente

Para bloqueos de giro y bloqueos de espera pendientes, sincronizado es un bloqueo adaptativo. Cuando el conflicto de bloqueo no es grave, sincronizado es un bloqueo de giro, pero si el conflicto de bloqueo es grave, sincronizado se convertirá en un bloqueo pendiente.

4. Bloqueo justo y bloqueo injusto

Sincronizado es un bloqueo injusto. Cuando varios subprocesos intentan adquirir el mismo bloqueo, a sincronizado no le importa el orden en el que llega primero, pero todos los subprocesos en espera compiten por el bloqueo.

5. Cerraduras reentrantes y cerraduras no reentrantes

sincronizado es un bloqueo reentrante. Cuando un subproceso adquiere el bloqueo externamente, automáticamente adquirirá el bloqueo internamente sin caer en un estado de punto muerto.

sincronizado no es un bloqueo de lectura y escritura.

Preguntas de entrevista relacionadas

1) ¿Cómo entiende el bloqueo optimista y el bloqueo pesimista y cómo implementarlos específicamente?

El bloqueo pesimista cree que existe una alta probabilidad de conflicto cuando varios subprocesos acceden a la misma variable compartida y, de hecho, se bloqueará antes de cada acceso a la variable compartida.

El bloqueo optimista cree que la probabilidad de conflicto entre varios subprocesos que acceden a la misma variable compartida es baja. En realidad, no bloqueará, sino que intentará acceder directamente a los datos. Al acceder, identificará si los datos actuales tienen un conflicto de acceso.

La implementación del bloqueo pesimista es bloquear primero (por ejemplo, con la ayuda del mutex proporcionado por el sistema operativo), obtener el bloqueo y luego operar los datos. Si no se puede obtener el bloqueo, esperar.

La implementación del bloqueo optimista puede introducir un número de versión, que se utiliza para identificar si el acceso a los datos actuales entra en conflicto.

2) ¿Introducir bloqueo de lectura y escritura?

  • Los bloqueos de lectura y escritura bloquean las operaciones de lectura y las operaciones de escritura por separado.
  • Los bloqueos de lectura y los bloqueos de lectura no se excluyen entre sí.
  • Los bloqueos de escritura y los bloqueos de escritura se excluyen mutuamente.
  • Los bloqueos de escritura y los bloqueos de lectura son mutuamente excluyentes.
  • Los bloqueos de lectura y escritura se utilizan principalmente en escenarios de "lectura frecuente y escritura poco frecuente".

3) ¿Qué es un bloqueo de giro, por qué deberíamos utilizar la estrategia de bloqueo de giro y cuáles son sus desventajas?

Si la adquisición del candado falla, intente adquirir el candado nuevamente inmediatamente, haciendo un bucle infinito hasta que se adquiera el candado. Si el primer intento de adquirir el candado falla, el segundo intento se realizará en muy poco tiempo. Una vez que el candado sea liberado por otros hilos, puede obtener el bloqueo lo antes posible.

En comparación con colgar y esperar un candado,

Ventajas: No se renuncia a los recursos de la CPU. Una vez que se libera el bloqueo, se puede obtener lo antes posible, lo cual es más eficiente. Es muy útil en escenarios donde el tiempo de retención del bloqueo es relativamente corto.

Desventajas: si el bloqueo se mantiene durante mucho tiempo, se desperdiciarán recursos de la CPU

4) ¿Está sincronizada una cerradura reentrante?

Es una cerradura reentrante.

El bloqueo reentrante significa que bloquear dos veces seguidas no provocará un punto muerto.

La forma de lograr esto es registrar la identidad del hilo retenido por el candado en el candado y un contador (que registra el número de candados). Si se descubre que el hilo actualmente bloqueado es el hilo que sostiene el candado, el recuento se incrementará directamente.

Supongo que te gusta

Origin blog.csdn.net/m0_73888323/article/details/133418184
Recomendado
Clasificación