1. Algoritmo sin bloqueo
Los algoritmos sin bloqueo son algoritmos concurrentes que pueden generar sus subprocesos de manera segura no a través de generación de bloqueo, sino a través de formas de atomicidad nativas del hardware de bajo nivel, como comparaciones e intercambios. Los algoritmos sin bloqueo son extremadamente difíciles de diseñar e implementar, pero pueden proporcionar un mejor rendimiento y una mejor defensa contra problemas de supervivencia como el punto muerto y la inversión de prioridad. Utilice instrucciones de máquina atómica de bajo nivel para reemplazar cerraduras, como comparar e intercambiar (CAS).
2. Tecnología pesimista
El bloqueo exclusivo es una técnica pesimista que supone que ocurre el peor de los casos (si el bloqueo no está bloqueado, otros subprocesos destruirán el estado del objeto), e incluso si el peor de los casos no ocurre, el estado del objeto aún está protegido. un candado.
3. Tecnología optimista
Monitoreo de conflictos de dependencia. Actualice primero. Si ocurre un conflicto durante el monitoreo, abandone la actualización y vuelva a intentarlo; de lo contrario, la actualización se realiza correctamente. Ahora los procesadores tienen instrucciones atómicas de lectura, modificación y escritura, como comparar e intercambiar (CAS, comparar). -y- intercambiar).
4.Operación CAS
CAS tiene 3 operandos, el valor de memoria V, el antiguo valor esperado A y el nuevo valor a modificar B. Si y solo si el valor esperado A y el valor de memoria V son iguales, modifique el valor de memoria V a B; de lo contrario, no haga nada. El patrón de uso típico de CAS es: primero lea A de V y calcule el nuevo valor B en función de A, y luego use CAS para cambiar atómicamente el valor en V de A a B (siempre que ningún hilo cambie el valor de V durante este período) valor a otro valor).
Listado 3. Código que ilustra el comportamiento (pero no el rendimiento) de comparar e intercambiar. Copie el siguiente código:
clase pública CAS simulada {
valor int privado;
público sincronizado int getValue() { valor de retorno }
público sincronizado int compareAndSwap (int valor esperado, int nuevo valor) {
int valorantiguo = valor;
si (valor == valor esperado)
valor = nuevoValor;
devolver valor antiguo;
}
}
Listado 4. Utilice comparar e intercambiar para implementar el código de copia de contador. El código es el siguiente:
clase pública CasCounter {
valor CAS simulado privado;
público int getValue() {
valor de retorno.getValue();
}
incremento int público() {
int valorantiguo = valor.getValue();
mientras (value.compareAndSwap(oldValue, oldValue + 1) != oldValue)
valorantiguo = valor.getValue();
devolver valor antiguo + 1;
}
}
5. Variables atómicas
Las variables atómicas admiten operaciones de actualización atómica sin protección de bloqueo y la capa subyacente se implementa mediante CAS. Hay 12 variables atómicas en total, que se pueden dividir en 4 grupos: clase escalar, clase de actualización, clase de matriz y clase de variable compuesta. Las variables atómicas más utilizadas son las clases escalares: AtomicInteger, AtomicLong, AtomicBoolean y AtomicReference. CAS es compatible con todos los tipos.
6. Comparación de rendimiento: bloqueos y variables atómicas
En condiciones de contención baja a media, las variables atómicas pueden proporcionar una alta escalabilidad y el rendimiento de las variables atómicas excede el de los bloqueos. En condiciones de contención de alta intensidad, los bloqueos pueden evitar la contención de manera más efectiva y el rendimiento de los bloqueos excederá el rendimiento de los atómicos; variables. Pero en una situación práctica más realista, el rendimiento de las variables atómicas superará el rendimiento de las cerraduras.