Cuatro, BLOQUEO
1. Los 4 estados de la cerradura
[1] Optimización de bloqueo
Para reducir el costo de rendimiento de adquirir y liberar candados, JDK6 introdujo "candados sesgados" y "candados ligeros"
Como resultado, la cerradura tiene 4 estados, que se actualizarán con la competencia de cerraduras. La cerradura se puede actualizar pero no degradar. La actualización de la cerradura se llama "expansión de la cerradura"
[2] Estado de bloqueo parcial
En la mayoría de los casos, el bloqueo no solo no tiene competencia de subprocesos múltiples, sino que también siempre es adquirido por el mismo subproceso varias veces
Para mejorar el rendimiento de esta situación, se introduce un bloqueo de polarización
El ID de subproceso de la polarización de bloqueo se almacena en el registro de bloqueo en el encabezado del objeto y el marco de la pila. Cuando un subproceso entra y sale del bloque de sincronización, no necesita realizar operaciones CAS para bloquear y desbloquear, y determinar directamente si hay es una marca de palabra en el encabezado del objeto Apunta al bloqueo de sesgo del hilo actual
Si existe, el hilo ha adquirido el bloqueo, si no existe, el bloqueo se expande a un bloqueo ligero
El bloqueo de polarización está habilitado de forma predeterminada en JDK6 y JDK7, pero debe activarse unos segundos después de que se inicie el programa.
Si necesita desactivar este retraso, use el parámetro JVM
-XX:BiasedLockingStartupDelay=0
Si desactiva el bloqueo de polarización, utilice el parámetro JVM
-XX:-UseBiasedLocking
[3] Estado de bloqueo ligero
Bloqueo: la JVM crea un espacio para almacenar la marca de bloqueo en el marco de la pila del hilo actual y copia la palabra de marca desplazada en el encabezado del objeto. Si tiene éxito, significa que el subproceso actual adquiere el bloqueo con éxito. Si falla, significa que hay competencia de bloqueo. El subproceso actual intentará usar el giro para adquirir el bloqueo.
Desbloqueo: utilice la operación CAS atómica para reemplazar la palabra de marca desplazada de nuevo a la cabeza del objeto. Si tiene éxito, significa que no hay competencia de cerraduras. Si falla, significa que hay competencia de cerraduras, lo que hará que la cerradura se expanda a una cerradura de peso pesado.
[4] Contraste
Tipo de bloqueo | ventaja | Desventaja | Escena aplicable |
---|---|---|---|
Bloqueo de sesgo | No hay espera adicional para bloquear y desbloquear, y hay una diferencia de nanosegundos (1 nanosegundo = 1000 * 1000 milisegundos) en comparación con el método de ejecución sin bloqueo |
Si hay competencia de cerraduras, traerá un consumo adicional de cerraduras de revocación |
Solo un hilo accede al bloque sincronizado |
Cerradura ligera | Los hilos de la competencia no se bloquearán, lo que mejora la velocidad de respuesta del programa. |
Si el hilo no ha podido adquirir el bloqueo, el uso de spin consumirá CPU |
La búsqueda de la velocidad de respuesta, la velocidad de ejecución del bloque de sincronización es muy rápida |
Bloqueo de peso pesado | La competencia de subprocesos no usa giro y no consume CPU | Los subprocesos en competencia se bloquearán, lo que reducirá la velocidad de respuesta |
Perseguir el rendimiento, el tiempo de ejecución del bloque síncrono es más largo |
2. Cerradura justa y cerradura injusta
Fair lock: Cuando cada hilo adquiere un bloqueo, primero verifica la cola de espera mantenida por el bloqueo, si la cola está vacía o el hilo actual es el primero (cabeza) en la cola, el hilo adquiere el bloqueo. En el futuro, me recuperarán de la cola de espera de acuerdo con el principio FIFO (cola para esperar para adquirir el bloqueo)
Bloqueo injusto: cada hilo puede intentar adquirir el bloqueo
sincronizado es un bloqueo injusto
java.util.concurrent.locks.ReentrantLock es un bloqueo injusto creado por un constructor sin parámetros. Pase un constructor parametrizado y pase verdadero, el bloqueo es un bloqueo justo
3. Bloqueo reentrante
Los bloqueos reentrantes también se denominan bloqueos recursivos , que se refieren a los subprocesos que han adquirido el bloqueo. Al ejecutar el método de sincronización en el método de sincronización, el método se puede ejecutar directamente sin volver a adquirir el bloqueo.
sincronizados y java.util.concurrent.locks.ReentrantLock son bloqueos reentrantes
4. Bloqueo giratorio
Los subprocesos intentan adquirir bloqueos girando para reducir la sobrecarga del cambio de contexto del subproceso
class CasLock {
private final AtomicReference<Thread> reference = new AtomicReference<Thread>();
public void lock() {
for (;;) {
if (tryAcquire()) {
break;
}
}
}
public void unlock() {
for (;;) {
if (tryRelease()) {
break;
}
}
}
private boolean tryAcquire() {
Thread thread = Thread.currentThread();
return reference.compareAndSet(null, thread);
}
private boolean tryRelease() {
Thread thread = Thread.currentThread();
return reference.compareAndSet(thread, null);
}
}
5. Cerraduras compartidas y cerraduras exclusivas
Bloqueo compartido: varios subprocesos pueden adquirir el bloqueo
Bloqueo exclusivo: el bloqueo solo puede ser exclusivo de un hilo
El bloqueo de lectura de java.util.concurrent.locks.ReentrantReadWriteLock es compartido por el hilo, mientras que el bloqueo de escritura lo comparte exclusivamente el hilo.
sincronizados y java.util.concurrent.locks.ReentrantLock son bloqueos exclusivos
6. Bloqueo de lectura y escritura
java.util.concurrent.locks.ReentrantReadWriteLock
Bloqueo de lectura-escritura, bloqueo de lectura y bloqueo de escritura coexisten, bloqueo de lectura compartido, bloqueo de escritura exclusivo
7. Compatibilidad de subprocesos y oposición de subprocesos
Compatibilidad con subprocesos: el objeto que se va a utilizar no es seguro para subprocesos, pero se pueden utilizar varios métodos seguros para subprocesos para garantizar que el objeto sea seguro para subprocesos en un entorno de subprocesos múltiples.
Oposición de subprocesos: el objeto que se va a operar es seguro para subprocesos, pero debido a que la solicitud simultánea de varios subprocesos no es segura para subprocesos cuando el objeto se opera en un entorno de subprocesos múltiples, el objeto de operación en sí mismo se vuelve inseguro para subprocesos
Ejemplos de la línea Java hostil: método de eliminación de la clase de subproceso (@Deprecated) suspend
y resume
puede causar un interbloqueo