Principios de diseño de simultaneidad del análisis de casos de API de simultaneidad de Java

Tabla de contenido

0, Intersticial 2020CSDN blog star vote news

1. Apertura

Segundo, concurrencia y paralelismo

Tres programas concurrentes traen problemas clave

1. Competencia de datos

2. Punto muerto

3. Livelock

4. Recursos insuficientes

5. Cambio de prioridad

Cuatro, API de simultaneidad de Java (detallada)

1. Simultaneidad básica

2. Mecanismo de sincronización

3. Actuador

4. Marco de bifurcación / unión

5. Estructura de datos concurrentes

Cinco, patrón de diseño concurrente

1. Modelo de señal

2. Modo de encuentro

3. Modo mutuamente excluyente

4. Modo de bloqueo de lectura y escritura

5. Modo de grupo de subprocesos

6. Modo de almacenamiento local de subprocesos

Seis, resumen final


0, Intersticial 2020CSDN blog star vote news

Recientemente (del 11 al 24 de enero), la selección de estrellas del blog 2020CSDN está en marcha. Como Xiaobai de un año, tuve la suerte de ser seleccionado como Top 200. En primer lugar, estoy muy agradecido con el funcionario de CSDN por elegir yo. Pensé que estaba llegando. Únete a la diversión y mira a los grandes PK ^ _ ^ #.

Según la situación de lucha de los grandes jefes en los últimos 4 días, los diez grandes jefes están sentados de manera muy constante, ¡y tienen que ser admirables y elogiados! Se puede ver la fuerza real, la cantidad de artículos no es importante, ¡pero la calidad es más importante! Todo habla con datos, como se muestra en la figura:

Desde 2021-01-15 14:40:01

Mirando los datos asombrosos de los grandes, hay una gran brecha conmigo. No puedo evitar sentir que Xiaobai solo espera estar en el Top 100. Espero que los grandes, amigos, fanáticos y otros pequeños blancos como yo, que veo esta noticia puede superarlo. Déjame votar unánimemente por mí. ¡Celebremos y avancemos juntos en el Año Nuevo, y todo saldrá bien! ^ _ ^ #

Dirección de votación: https://bss.csdn.net/m/topic/blog_star2020/detail?username=charzous

O escanee el código para votar:

Punto clave: todos los votos se registrarán y es fácil pedir ayuda a Charzous después de emitir un voto (pistas locas sobre los votos de escrutinio)

Desde ahora hasta el 24, puedes votar todos los días. Cuantos más votos tengas, más alta será la clasificación de las contribuciones. ¡Me acordaré de tu nombre!

1. Apertura

En muchas publicaciones de blog sobre programación de redes Java que escribí antes, inicialmente se utilizó la tecnología de subprocesos múltiples, que es un caso de aplicación relacionado con la concurrencia de Java. Ahora, necesitamos aprender algunos principios de la programación concurrente, comprender los entresijos y tener una comprensión relativamente más profunda de los principios del diseño concurrente. Y descubrí que después de aprender la programación de redes Java, con una comprensión práctica y luego de aprender sus principios relacionados, es más fácil comprender el conocimiento de los principios.

Este artículo registra los conocimientos importantes que he aprendido y hace que sea más fácil verlos después de clasificarlos, ¡y también es conveniente para revisarlos y estudiarlos más tarde!

Segundo, concurrencia y paralelismo

Es sorprendente que los dos conceptos de concurrencia y paralelismo hayan sido estudiados en el transcurso de los sistemas operativos, en ese momento solo eran estudios teóricos a nivel de sistema operativo, sin involucrar escenarios reales de aplicación y lenguajes de programación. Ahora revise el conocimiento para estudiarlo más a fondo y descubra que es más práctico de entender.

Existen muchas definiciones de simultaneidad y paralelismo. A continuación, se incluyen algunas que son fáciles de entender:

Concurrente se refiere a dos o más eventos que ocurren dentro del mismo intervalo de tiempo, la programación multicanal, significa al mismo tiempo una pluralidad de tareas que se ejecutan simultáneamente dentro del programa, que se ejecuta simultáneamente en la macro, micro serie de.

Paralelo significa que simultáneamente se realizan múltiples tareas en un microscópico, ocurre en el mismo momento en el tiempo . Obviamente, si se requieren múltiples tareas del programa para ejecutarse en paralelo, se necesitan múltiples procesadores En un sistema de un solo procesador, solo hay simultaneidad pero no paralelismo.

 Usar un solo núcleo para ejecutar múltiples tareas en un solo procesador es concurrencia , y el programador del sistema operativo cambiará rápidamente de una tarea a otra, por lo que parece que todas las tareas se ejecutan al mismo tiempo. La ejecución simultánea de múltiples tareas en diferentes procesadores o núcleos de procesador al mismo tiempo es paralela .

Lo más importante es el principio y diseño de concurrencia, lo que conduce a un concepto importante de "sincronización" en concurrencia .

La sincronización es un mecanismo para coordinar dos o más tareas para obtener los resultados esperados. incluir:

  1. Control de sincronización : dependencias de tareas. Cuando la ejecución de una tarea debe depender del final de otra tarea, la segunda tarea no puede comenzar antes de la finalización de la primera.
  2. Sincronización de acceso a datos : cuando dos o más tareas acceden a una variable compartida, solo una tarea puede acceder a la variable en cualquier momento.

Un concepto estrechamente relacionado con la sincronización es la sección crítica , que es un fragmento de código que se utiliza para garantizar que solo una tarea pueda acceder a los recursos compartidos en cualquier momento. La exclusión mutua es el mecanismo utilizado para asegurar esta sección crítica.

Tres programas concurrentes traen problemas clave

La redacción y el diseño de programas concurrentes deben trabajar mucho en el mecanismo de sincronización / exclusión mutua para garantizar la correcta ejecución de los programas concurrentes. Por lo tanto, es necesario prestar atención a las siguientes cuestiones clave.

1. Competencia de datos

En pocas palabras, varias tareas escriben en variables compartidas y no hay una sección crítica del mecanismo de sincronización como restricción, y hay competencia de datos en el programa.

public class Account{
    private float balance;
    public void modify(float difference){
        float value=this.balance;
        this.balance=value+difference;
    }
}

 Por ejemplo, en el ejemplo anterior, si hay dos tareas que ejecutan el mismo objeto Cuenta para la operación de modificación, el saldo inicial = 1000 y el saldo final debe ser 3000, pero si las dos tareas ejecutan la primera instrucción de la modificación al mismo tiempo, ejecutan la primera declaración al mismo tiempo. Dos oraciones, el resultado se convierte en 2000. Por lo tanto, la clase Account no es segura para subprocesos y no implementa operaciones atómicas ni mecanismos de sincronización.

2. Punto muerto

En pocas palabras, dos o más tareas están esperando un recurso liberado por otro subproceso, y este subproceso también está esperando el recurso liberado por la tarea anterior, tal programa concurrente tiene un punto muerto.

Cuando se satisfacen completamente las siguientes condiciones, se producirá un interbloqueo.

  1. Condiciones mutuamente excluyentes : el recurso en el punto muerto no se puede compartir y solo una tarea puede usar el recurso en un período de tiempo.
  2. Condiciones de solicitud y retención : la tarea retuvo al menos un recurso, pero se realizó una nueva solicitud y el recurso debe liberarse. En este momento, la tarea está bloqueada y esperando, y los recursos que ha adquirido no se liberarán. .
  3. Condiciones de no privación : los recursos solo pueden ser liberados por las tareas que los contienen.
  4. Condición de espera circular : la tarea 1 está esperando el recurso ocupado por la tarea 2 y la tarea 2 está esperando el recurso ocupado por la tarea 3, ..., por lo que hay una espera circular.

Los métodos para lidiar con los interbloqueos son: prevención, evitación, detección y liberación. Estos cuatro métodos básicos tienen algoritmos de implementación específicos. 

3. Livelock

Si hay dos tareas en el sistema que siempre cambian de estado debido al comportamiento de la otra, se producirá un bloqueo.

Por ejemplo, las tareas 1 y 2 requieren los recursos 1 y 2. En este momento, la tarea 1 posee el recurso 1 y se bloquea, y la tarea 2 posee el recurso 2 y se bloquea. Cuando no pueden acceder a los recursos requeridos, liberan sus recursos y comienzan un nuevo ciclo, de modo que continúa indefinidamente, y ninguna de las tareas terminará su proceso de ejecución.

4. Recursos insuficientes

Livelock es una situación de recursos insuficientes, cuando la tarea no puede obtener los recursos necesarios en el sistema para continuar la tarea.

La solución es garantizar el principio de equidad .

5. Cambio de prioridad

Cuando una tarea de baja prioridad contiene los recursos requeridos por una tarea de alta prioridad, se producirá una inversión de prioridad y la tarea de baja prioridad se ejecutará por adelantado.

Cuatro, API de simultaneidad de Java (detallada)

Java contiene una gran cantidad de API simultáneas, que se pueden utilizar de forma flexible durante la programación simultánea.

1. Simultaneidad básica

  1. Clase de subproceso: describe todos los subprocesos que ejecutan aplicaciones Java concurrentes.
  2. Interfaz ejecutable: otra forma de crear programas simultáneos en Java.
  3. Clase ThreadLocal: se utiliza para almacenar variables pertenecientes a un hilo. (Se usa cuando no hay mecanismo de sincronización)
  4. Interfaz ThreadFactory: la clase base que implementa el patrón de diseño Factory para crear subprocesos personalizados.

2. Mecanismo de sincronización

El mecanismo de sincronización concurrente de Java admite la definición de una sección crítica para acceder a un recurso compartido; diferentes tareas se sincronizan en un punto común.

  1. palabra clave sincronizada : puede definir una sección crítica en un bloque de código o un método completo.
  2. Interfaz de bloqueo: proporciona operaciones de sincronización más ricas y flexibles. Entre ellos, ReentantLock se usa para implementar un bloqueo de asociación condicional; ReentantRead-WriteLock separa las operaciones de lectura y escritura; StampedLock incluye un modo para controlar el acceso de lectura / escritura, que es una nueva característica de Java 8.

Los siguientes son relativamente desconocidos:

  1. Clase CountDownLatch: permite que múltiples tareas esperen el final de múltiples operaciones.
  2. Clase CyclicBarrier: permite que varios subprocesos se sincronicen en un punto común.
  3. Categoría Phaser: permite controlar la ejecución de tareas que se dividen en múltiples fases. Todas las tareas no pueden ingresar a la siguiente etapa antes de completar las subtareas de la etapa actual.

3. Actuador

  1. Interfaz de ejecutor e interfaz de ExecutorService: incluido el método de ejecución común.
  2. Clase ThreadPoolExecutor: puede definir el número máximo de tareas ejecutoras del grupo de subprocesos.
  3. Clase ScheduledThreadPoolExecutor: un tipo especial de ejecutor que ejecuta tareas después de un retraso o ejecuta tareas periódicamente.
  4. Interfaz invocable: una interfaz alternativa a la interfaz Runnable que proporciona un valor de retorno.
  5. Interfaz futura: contiene métodos para obtener el valor de retorno de Callable y controlar su estado.

4. Marco de bifurcación / unión

Este marco define un actuador especial, especialmente para los problemas de divide y vencerás, y proporciona un mecanismo de optimización con una sobrecarga baja. Clases e interfaces principales:

  1. ForkJoinPool: Implementó un ejecutor para ejecutar tareas.
  2. ForkJoinTask: Tareas que se pueden ejecutar en las clases anteriores.
  3. ForkJoinWorkerThread: un hilo que está listo para realizar tareas en la clase 1.

5. Estructura de datos concurrentes

Las estructuras de datos de uso común en Java, como ArrayList, Map, HashMap, etc., no se pueden usar en programas concurrentes, porque no hay un mecanismo de sincronización y no es seguro para subprocesos. Si uno mismo adopta el mecanismo de sincronización, aumenta la sobrecarga computacional del programa.

Por lo tanto, Java proporciona estructuras de datos especiales en programas simultáneos, que son seguros para subprocesos, y hay dos categorías principales:

  1. Estructura de datos de bloqueo: contiene métodos que bloquean las tareas de llamada, por ejemplo, cuando se obtiene el valor, el resultado de los datos está vacío.
  2. Estructura de datos sin bloqueo: la operación se puede realizar inmediatamente sin bloquear la tarea de llamada.

Estructuras de datos concurrentes de uso común (seguridad de subprocesos):

  1. ConcurrentHashMap: tabla hash sin bloqueo ( otras estructuras de datos que comienzan con la palabra clave Concurrent )
  2. ConcurrentLinkedDeque: lista de no bloqueo
  3. LinkedBlockQueue: cola de bloqueo
  4. CopyOnWriteArrayList: lectura y lectura compartida, escritura y escritura mutuamente excluyentes, lectura y escritura mutuamente excluyentes.
  • Implementó la interfaz de lista
  • Tiene un bloqueo ReentrantLock = new ReentrantLock ();
  • La capa inferior es una matriz declarada con transitorios volátiles
  • Separación de lectura y escritura, copie una nueva matriz al escribir y asigne la nueva matriz a la matriz después de insertar, modificar o eliminar operaciones

     5. PriorityBlockingQueue: cola de bloqueo, clasificación de elementos según la prioridad.

     6. AtomicBoolean, AtomicInteger, AtomicLong y AtomicReference: realización atómica de tipos de datos básicos de Java. (Se pueden usar variables atómicas en lugar de sincronización)

Cinco, patrón de diseño concurrente

1. Modelo de señal

La realización de este modo de curso adopta semáforo o exclusión mutua, ReentrantLock o Semaphore en Java, o métodos de espera y notificación de clase Object.

public void task1(){
    section1();
    commonObject.notify();
}

public void task2(){
    commonObject.wait();
    section2();
}

El método section2 siempre se ejecuta después de section1. 

2. Modo de encuentro

En el modo de promoción de señal, la primera tarea esperará a que se complete una actividad de la segunda tarea, mientras que la segunda tarea también esperará a que se complete una actividad de la primera tarea. La diferencia radica en el uso de dos objetos .

public void task1(){
    section1_1();
    commonObject1.notify();
    commonObject2.wait();
    section1_2();
}

public void task2(){
    section2_1();
    commonObject2.notify();
    commonObject1.wait();
    section2_2();
}

La secuencia de declaraciones no se puede modificar, de lo contrario puede producirse un punto muerto.

 section2_2 siempre se ejecuta después de section1_1, y section1_2 siempre se ejecuta después de section2_1.

3. Modo mutuamente excluyente

El mecanismo de exclusión mutua se utiliza para realizar la sección crítica y garantizar que las operaciones sean mutuamente excluyentes.

public void task1() {
    preSection();
    try {
        lockObject.lock();//临界段开始
        section();
    }catch (Exception e){
        ……
    }finally {
        lockObject.unlock();//临界段结束
        postSection();
    }
}

4. Modo de bloqueo de lectura y escritura

Este modo define un bloqueo especial que contiene dos bloqueos internos: uno para operaciones de lectura y otro para operaciones de escritura.

Las características de la cerradura: leer y leer compartir, escribir y escribir exclusión mutua, leer y escribir exclusión mutua.

La clase ReentrantReadWriteLock de la API de concurrencia de Java implementa este patrón

5. Modo de grupo de subprocesos

Este modo es muy utilizado y reduce la sobrecarga de crear subprocesos para cada tarea cada vez, está compuesto por un conjunto de subprocesos y una cola de tareas a ejecutar. La interfaz ExceutorService puede implementar este modo.

6. Modo de almacenamiento local de subprocesos

La clase ThreadLocal en Java implementa variables locales de subprocesos, que pueden usar almacenamiento local de subprocesos, y cada subproceso accederá a una instancia diferente de la variable.

Seis, resumen final

A continuación, se muestra el diseño de algoritmos concurrentes:

1. Utilice la API concurrente de Java segura para subprocesos

2. Utilice variables de subprocesos locales en clases estáticas y ocasiones compartidas

3. Evite el punto muerto: clasifique las cerraduras

4. Usa variables atómicas

 

En este artículo, registré el conocimiento clave para aprender los principios de diseño concurrente, así como algunas API de programación concurrente de Java de uso común e importantes. Después de aprender los conocimientos teóricos, tengo una comprensión más profunda de esta parte. Si puedo agregar proyectos prácticos o específicos El análisis de casos puede considerarse un verdadero dominio. Por lo tanto, también encontré un caso más práctico para la búsqueda de archivos de práctica, que se registrará en detalle en el próximo blog. ¡Espero que la combinación de teoría y práctica mejore aún más la comprensión del conocimiento!

Si cree que es bueno, bienvenido a "un clic, tres vínculos", haga clic en Me gusta, marque como favorito, siga, comente directamente si tiene alguna pregunta, e intercambie y aprenda.


Mi blog de CSDN: https://blog.csdn.net/Charzous/article/details/112603639

Supongo que te gusta

Origin blog.csdn.net/Charzous/article/details/112603639
Recomendado
Clasificación