AQS: AbstractQueuedSynchronizer

AQS está bajo el paquete java.util.concurrent.locks

java.util.concurrent.locks mejora en gran medida el rendimiento concurrente, AQS se considera el núcleo de JUC

CountDownLatch (temporizador de cuenta regresiva) -> Clase de herramienta de sincronización para coordinar la sincronización entre múltiples hilos. Generalmente se usa para controlar la espera de subprocesos, puede hacer que un determinado subproceso espere hasta que finalice la cuenta regresiva y luego comience la ejecución. Se usa para controlar uno o más subprocesos para esperar varios subprocesos . Se mantiene un contador cnt. Cada vez que se llama al método countDown (), el valor del contador se reduce en 1 y se reduce a 0. Los hilos que están esperando por llamar al método wait () se despertarán. Condición de Python!

1  clase pública  CountDownLatch {
 2 / ** 3 Control de sincronización para CountDownLatch.
4 Utiliza el estado AQS para representar el recuento.
5 * / 6 La clase final privada estática Sync extiende 7 AbstractQueuedSynchronizer {
 8 9     }
 10 } 
   
         
      
 

CyclicBarrier (barrera cíclica) -> Deje que un grupo de hilos se bloquee cuando alcancen una barrera (punto de sincronización). La barrera no se abrirá hasta que el último hilo llegue a la barrera, y todos los hilos interceptados por la barrera continuarán funcionando. Se usa para controlar varios subprocesos para esperar el uno al otro, solo cuando llegan varios subprocesos, estos subprocesos continuarán ejecutándose . Similar a CountdownLatch, se logra manteniendo contadores. Después de que el subproceso ejecuta el método await (), el contador disminuirá en 1 y esperará hasta que el contador sea 0. Todos los subprocesos que están esperando mientras se llama al método wait () pueden continuar la ejecución. Una diferencia entre CyclicBarrier y CountdownLatch es que el contador de CyclicBarrier se puede reciclar llamando al método reset () , por lo que se llama barrera de ciclo. Python Event!

CyclicBarrier tiene dos constructores, donde las partes indican el valor inicial del contador, y barreraAcción se ejecutará una vez cuando todos los hilos lleguen a la barrera.

Semaphore (Semaphore) -> Semaphore es similar al semáforo en el sistema operativo, puede controlar el número de hilos de acceso a recursos mutuamente excluyentes. Tanto los bloqueos sincronizados como los reentrantes permiten que solo un hilo acceda a la vez, y el semáforo puede permitir que múltiples hilos accedan a la vez

 

 

AQS es un marco para construir bloqueos y sincronizadores . El uso de AQS puede construir fácil y eficientemente una gran cantidad de sincronizadores ampliamente utilizados, como ReentrantLock, Semaphore y otros como ReentrantReadWriteLock, SynchronousQueue, FutureTask, etc. Se basa en AQS.

Análisis del principio AQS

Idea central: si el recurso compartido solicitado está inactivo, establezca el subproceso de recurso solicitado actualmente como un subproceso de trabajo válido y establezca el recurso compartido en el estado bloqueado. Si el recurso compartido solicitado está ocupado, entonces se requiere un mecanismo de bloqueo de subprocesos en espera y asignación de bloqueo cuando se despierta.Este mecanismo AQS se implementa con un bloqueo de cola CLH, es decir, un subproceso que no puede obtener temporalmente un bloqueo se agrega a la cola.

La cola CLH es una cola virtual de dos vías (la cola virtual de dos vías no tiene una instancia de cola, solo la asociación entre nodos). AQS es encapsular cada subproceso que solicita recursos compartidos en una cola de bloqueo CLH para lograr la asignación de bloqueo

AQS utiliza una variable de miembro int para indicar el estado de sincronización y completa el trabajo en cola del subproceso de adquisición de recursos a través de la cola FIFO incorporada. AQS usa CAS para realizar operaciones atómicas en el estado de sincronización para modificar su valor.

private int voltile int state; // Variables compartidas, utilice la modificación volátil para garantizar la visibilidad del hilo

La información del estado se opera a través de getState, setState, compareAndSetState del tipo protegido

1  // Devuelve el valor actual del estado de sincronización 
2  protegido  final  int getState () {
 3      estado de retorno ;
 4  }
 5  
6  // Establece el valor del estado de sincronización 
7  protegido  final  vacío setState ( int newState) {
 8      state = newState;
 9  }
 10  
11  // Atómicamente (operación CAS) establezca el valor del estado de sincronización en la actualización del valor dado si el valor del estado de sincronización actual es igual al esperado (valor esperado) 
12  protegido  booleano final  compareAndSetState ( int wait , int update) {
 13 return     unsafe.compareAndSwapInt ( this , stateOffset, expect, update);
14 }

Cómo AQS comparte recursos

Exclusivo-> Solo se puede ejecutar un hilo, como ReentrantLock. Se puede dividir en bloqueo justo y bloqueo injusto

    Bloqueo justo: de acuerdo con el orden de cola de los subprocesos en la cola, el primero obtiene el bloqueo primero

    Bloqueo injusto: cuando el subproceso quiere adquirir el bloqueo, ignora el orden de la cola y toma el bloqueo directamente

Compartir-> Se pueden ejecutar múltiples hilos simultáneamente, como Semaphore / CountDownLatch

Diferentes sincronizadores personalizados compiten por recursos compartidos de diferentes maneras. Cuando se implementa el sincronizador personalizado, solo necesita implementar la forma de adquirir y liberar el estado del recurso compartido. En cuanto al subproceso específico que espera el mantenimiento de la cola (como la imposibilidad de obtener el recurso para entrar en la cola / despertar la cola, etc.), AQS se ha implementado en la parte superior

 

AQS usa el patrón de método de plantilla en la parte inferior

El diseño del sincronizador se basa en el patrón del método de la plantilla. Si necesita personalizar el sincronizador, la forma general es la siguiente:

1. El usuario hereda AbstractQueuedSynchronized y reescribe el método especificado (para la adquisición y liberación del estado de recurso compartido)

2. Combine AQS en la implementación de un componente de sincronización personalizado y llame a su método de plantilla, y estos métodos de plantilla llamarán a los métodos reescritos por el usuario.

1  // AQS usa el modo de método de plantilla. Al personalizar el sincronizador, debe reescribir los siguientes métodos de plantilla proporcionados por AQS: 
2  
3 isHeldExclusively () // Si el hilo está monopolizando los recursos, solo necesita usar la condición 
4  
5 tryAcquire ( int ) // Método exclusivo, intente obtener recursos, devuelva verdadero si tiene éxito, falso 
6 tryRelease ( int ) // Método exclusivo, intente liberar recursos, devuelva verdadero si tiene éxito, falso 
7 tryAcquiredShared ( int ) // Método de intercambio, intente obtener recursos. El número negativo significa falla, 0 significa éxito, pero no hay recursos restantes disponibles, el número positivo significa éxito y hay recursos restantes 
8 tryReleaseShared ( int ) // Modo de compartir, intenta liberar recursos, el éxito devuelve verdadero, falla falso

Por defecto, cada método arroja UnsupportedOperationException. La implementación de estos métodos debe ser internamente segura para subprocesos y, en general, debe ser corta en lugar de bloquear. Los otros métodos en la clase AQS son finales, por lo que no pueden ser utilizados por otras clases, solo estos métodos pueden ser utilizados por otras clases

Tomando ReentrantLock como ejemplo, el estado se inicializa a 0, lo que indica un estado desbloqueado. Cuando A thread lock (), llamará a tryAcquire () para monopolizar el bloqueo y el estado + 1. Después de eso, otros subprocesos fallarán cuando tryAcquire (), hasta que un subproceso de desbloqueo () establezca = 0 (es decir, libere el bloqueo), otros subprocesos tendrán la oportunidad de adquirir el bloqueo. Por supuesto, antes de liberar el bloqueo, el mismo hilo A puede adquirir repetidamente el bloqueo, que es el concepto de reentrada.

Tome CountDownLatch como ejemplo, la tarea se divide en N subprocesos para ejecutar, y el estado también se inicializa en N (tenga en cuenta que N debe ser coherente con el número de subprocesos). Los subprocesos N se ejecutan en paralelo. Después de ejecutar cada subproceso, countDown () se realiza una vez y el estado se reducirá en 1 CAS (Comparar e intercambiar). Después de que se ejecuten todos los subprocesos (es decir, estado = 0), el subproceso principal de llamada será unpark (), y luego el subproceso principal de llamada volverá de la función wait () para continuar las acciones posteriores

 

JUC otros componentes

FutureTask: Al presentar Callable, sabemos que puede tener un valor de retorno, y el valor de retorno está encapsulado por Future. FutureTask implementa la interfaz RunnableFuture, que hereda de las interfaces Runnable y Future, lo que permite que FutureTask se ejecute como una tarea y un valor de retorno.

FutureTask se puede utilizar para obtener el resultado de la ejecución de forma asincrónica o cancelar el escenario de ejecución de la tarea. Cuando una tarea informática necesita ser ejecutada por un largo tiempo, puede usar FutureTask para encapsular la tarea, y el hilo principal obtendrá el resultado después de completar su tarea.

 

BlockingQueue :

  • Cola FIFO: LinkedBlockingQueue, ArrayBlockingQueue (longitud fija)
  • Cola de prioridad: PriorityBlockingQueue

Proporciona métodos take () y put () de bloqueo: si la cola está vacía, take () se bloqueará hasta que haya contenido en la cola; si la cola está llena, put () se bloqueará hasta que la cola tenga una posición libre.

 

ForkJoin :

Se utiliza principalmente en la computación paralela, similar al principio de MapReduce, divide las tareas informáticas grandes en múltiples tareas pequeñas para la computación paralela. ForkJoin utiliza ForkJoinPool para comenzar, es un grupo de subprocesos especial, la cantidad de subprocesos depende de la cantidad de núcleos de CPU. ForkJoinPool implementa un algoritmo de robo de trabajo para mejorar la utilización de la CPU. Cada subproceso mantiene una cola de doble extremo para almacenar tareas que deben ejecutarse. El algoritmo de robo de trabajo permite que los subprocesos inactivos roben una tarea de las colas de dos extremos de otros subprocesos para su ejecución. La tarea robada debe ser la última tarea para evitar la competencia con el hilo al que pertenece la cola.

Supongo que te gusta

Origin www.cnblogs.com/liushoudong/p/12725992.html
Recomendado
Clasificación