Lectura de notas-programación concurrente de Java combat-Capítulo 2 seguridad de subprocesos

La premisa para problemas de seguridad de subprocesos:

Esta variable se puede modificar

Se accede a la variable mediante varios subprocesos

Cuando varios subprocesos acceden a la misma variable de estado variable sin la sincronización adecuada, se producirá un error en el programa. Hay tres formas de resolver este problema:

  • No comparta la variable de estado entre hilos
  • Modificar variables de estado a variables inmutables
  • Cuando visite, use la sincronización

1. ¿Qué es la seguridad de subprocesos?

Seguridad de subprocesos: cuando varios subprocesos acceden a una determinada clase, la clase puede comportarse correctamente, entonces la llamamos segura para subprocesos.

Los objetos sin estado deben ser seguros para subprocesos

(Con estado y sin estado: Con estado significa una clase con la función de almacenar datos. Sin estado significa que los atributos de la clase no almacenan datos)

2. Atomicidad

1. Condición de carrera: cuando varios subprocesos acceden al mismo recurso, el orden diferente de ejecución de los subprocesos dará como resultado resultados inconsistentes. En este momento, se produce una condición de carrera. Los recursos de código a los que acceden varios subprocesos se denominan secciones críticas.

  • Verifique primero y luego ejecute: haga un juicio basado en una observación que pueda fallar, o realice una operación determinada. Este tipo de condición de carrera se denomina verificación antes de la ejecución.

2. Condiciones de carrera en la inicialización diferida : la inicialización diferida inicializará el objeto cuando sea necesario para ahorrar memoria, al mismo tiempo, debemos asegurarnos de que el objeto se inicialice solo una vez. Sin embargo, en el caso de subprocesos múltiples, dos subprocesos ejecutan la condición de inicialización al mismo tiempo. Cuando la inicialización del primer subproceso no se completa, el segundo subproceso realizará el juicio de condición en este momento. El resultado es que el objeto no se ha inicializado, entonces el segundo subproceso realizará la inicialización nuevamente. Se han producido problemas de seguridad de subprocesos en este momento. El código que debería haberse ejecutado una vez fue ejecutado una vez por dos subprocesos. Si hay otro hilo para juzgar las condiciones de inicialización antes de que se complete la inicialización del primer y segundo hilo. Luego se realizará una inicialización más. Esta es una situación que no queremos ver.

3. Operación compuesta: La combinación de varias acciones que deben realizarse atómicamente se llama operación compuesta. Por ejemplo, verifique primero y luego ejecute, hay un conjunto de acciones que se ejecutarán de forma atómica. Entonces, verifique primero y luego ejecute es una operación compuesta. Si queremos garantizar la seguridad de los subprocesos, debemos asegurarnos de que cada grupo de operaciones compuestas se ejecute de forma atómica. En términos generales, lograremos este objetivo mediante el bloqueo.

Tres, mecanismo de bloqueo

1. Bloqueo integrado : Java proporciona un mecanismo de bloqueo integrado para admitir la atomicidad: bloques de código sincronizados. El bloque de código de sincronización consta de dos partes: una es la referencia de objeto de la cerradura y la otra es el bloque de código de protección de la cerradura. El método modificado con la palabra clave Synchronized es un método de sincronización que incluye todo el cuerpo del método. El bloqueo de este bloque de código es una instancia de llamar a este método. Eso es esto. Cuando la modificación sincronizada es un método estático, el bloqueo del bloque de código es el objeto .CLASS de la clase actual.

2. Reentrante: cuando un hilo solicita un bloqueo mantenido por otro hilo, el hilo solicitante se bloqueará. Sin embargo, debido a que el bloqueo interno es reentrante, si un subproceso intenta adquirir un bloqueo que ya tiene, la solicitud tendrá éxito. Una forma de lograr la reentrada es asociar el bloqueo con un contador y un subproceso propietario. Cuando el contador es 0, el bloqueo no está retenido por ningún hilo. En este momento, cualquier hilo que solicite el bloqueo puede tener éxito. Al mismo tiempo, la JVM registrará el titular del bloqueo y establecerá el contador en 1. Cuando el mismo hilo vuelva a Al adquirir este bloqueo, el contador aumentará, y cuando el hilo sale del bloque de código de sincronización, el contador disminuirá hasta que el contador llegue a 0 y se libere el bloqueo.

3. Los beneficios de la reentrada : cuando la subclase anula el método de sincronización de la clase principal, como se muestra en el siguiente código. Al ejecutar doSomething de la subclase LoggingWidget, el hilo obtendrá el bloqueo. Cuando se ejecuta doSomething de la subclase, se vuelve a llamar a doSomething del padre. Si el bloqueo incorporado no es reentrante, el doSomething de la clase padre esperará para siempre. La reentrada evita este tipo de punto muerto.

public class Widget{
    
    
    public synchronized void doSomething(){
    
    
        ...
    }
}

public class LoggingWidget extends Widget{
    
    
    public synchronized void doSomething(){
    
    
        system.out.println("=================");
        super.doSomething();
    }
}

Cuarto, use un candado para proteger el estado

Las variables se pueden proteger mediante bloqueos, lo que garantiza que solo un subproceso esté operando esta variable a la vez. Solo cuando el subproceso completa la operación en la variable, otros subprocesos pueden operar en la variable.

5. Actividad y desempeño

  • El bloqueo puede garantizar la seguridad de nuestro programa. Debemos tener en cuenta la seguridad porque: se utiliza subprocesos múltiples para mejorar el rendimiento. En el caso de subprocesos múltiples, se producirán problemas de seguridad de subprocesos, por lo que debemos bloquear para garantizar la sincronización. Pero esto no significa que tengamos que sacrificar el rendimiento por la seguridad. Por lo tanto, debemos garantizar la seguridad del programa al tiempo que garantizamos su rendimiento. No sacrifique el rendimiento por la seguridad ciega. Entonces introducimos subprocesos múltiples y no tiene ningún sentido.
  • Por lo tanto, cuando bloqueamos, debemos hacer un juicio razonable sobre el tamaño del bloque de código de sincronización. En este punto, necesitamos encontrar un equilibrio entre seguridad, simplicidad y rendimiento. A menudo existen conflictos entre la simplicidad y el rendimiento.

Nota: Cuando realice cálculos u operaciones a largo plazo que pueden no completarse rápidamente (E / S de red o E / S de consola), no mantenga el candado

Supongo que te gusta

Origin blog.csdn.net/weixin_45373852/article/details/108726264
Recomendado
Clasificación