De hecho, me tomé el tiempo de estudiar la fuente real, por pura curiosidad, y la idea detrás de esto es bastante simple. La versión más reciente al momento de escribir esta publicación es 3.2.1.
Hay un almacenamiento intermedio que almacena eventos preasignados que contendrán los datos para que los consumidores los lean.
El búfer está respaldado por una matriz de indicadores (matriz de enteros) de su longitud que describe la disponibilidad de las ranuras de búfer (consulte más detalles para obtener más detalles). Se accede a la matriz como una java # AtomicIntegerArray, por lo tanto, a los fines de esta explicación, puede asumir que es una.
Puede haber cualquier número de productores. Cuando el productor desea escribir en el búfer, se genera un número largo (como cuando llama a AtomicLong # getAndIncrement, el disruptor realmente usa su propia implementación, pero funciona de la misma manera). Vamos a llamar esto generado por mucho tiempo a producerCallId. De manera similar, un ConsumerCallId se genera cuando un consumidor ENDS lee un slot desde un buffer. Se accede al consumidorCallId más reciente.
(Si hay muchos consumidores, se elige la llamada con el ID más bajo.)
estos ID se comparan entonces, y si la diferencia entre los dos es menor que el lado de tampón, se permite que el productor escribir.
(Si el producerCallId es mayor que la reciente consumerCallId + bufferSize, significa que el búfer está lleno, y el productor se ve obligado a autobús de esperar hasta que un punto esté disponible.)
Se asignará la productora la ranura en el buffer basado en su callId (que es prducerCallId modulo bufferSize, pero dado que el bufferSize es siempre una potencia de 2 (límite impuesto en la creación del buffer), la operación real utilizada es producerCallId & (bufferSize - 1)). Entonces es libre de modificar el evento en ese espacio.
(El algoritmo real es un poco más complicado, que implica el almacenamiento en caché reciente consumerId en una referencia atómica separada, con fines de optimización.)
Cuando se modificó el evento, el cambio se "publica". Al publicar la ranura respectiva en la matriz de banderas se completa con la bandera actualizada. El valor del indicador es el número del ciclo (producerCallId dividido por bufferSize (de nuevo desde que bufferSize es potencia de 2, la operación real es un cambio a la derecha).
De manera similar, puede haber cualquier número de consumidores. un consumidor quiere acceder al buffer, se genera un customerCallId (dependiendo de cómo se agregaron los consumidores al disruptor, el atómico utilizado en la generación de id se puede compartir o separar para cada uno de ellos). Este consumerCallId se compara con el más reciente productCallId , y si es menor de los dos, el lector puede progresar.
(Del mismo modo, si producerCallId es incluso para consumerCallId, significa que el buffer es empety y el consumidor está obligado a esperar. la espera está definida por un WaitStrate durante la creación del disruptor.)
Para consumidores individuales (los que tienen su propio generador de ID), lo siguiente que se verifica es la capacidad de consumir por lotes. Las ranuras en el buffer se examinan en orden desde el respectivo al consumidor CallId (el índice se determina de la misma manera que para los productores), a la correspondiente al productorCallId reciente.
Se examinan en un bucle comparando el valor de indicador escrito en la matriz de indicador, con un valor de marcador generado para el identificador de llamada del consumidor. Si las banderas coinciden, significa que los productores que llenan las máquinas tragamonedas han confirmado sus cambios. De lo contrario, el ciclo se interrumpe y se devuelve el valor de cambio commited más alto. Las ranuras de ConsumerCallId a recibidas en changeId se pueden consumir en lote.
Si un grupo de consumidores lee en conjunto (los que tienen un generador de id. Compartido), cada uno solo toma un solo identificador de llamada, y solo se verifica y se devuelve el espacio para dicho identificador de llamada.
Gracias Michael. Su reseña y los enlaces que proporcionó me ayudaron a tener una mejor idea de cómo funciona. El resto, creo que solo necesito dejarlo caer. – Shahbaz
hola Michael, por favor revisa mi respuesta para ver si hay errores. – irreputable
Todavía tengo preguntas: (1) ¿cómo funciona el 'compromiso'? (2) Cuando el buffer de anillo está lleno, ¿cómo detecta el productor que todos los consumidores han visto los datos para que el productor pueda volver a utilizar las entradas? – Qwertie