1. Longadder
Se usa de manera similar a AtomicLong, pero tiene un mejor rendimiento que AtomicLong.
Longadder y Atomiclong usan operaciones atómicas para mejorar el rendimiento. Sin embargo, la longadder realiza una separación de punto caliente basada en Atomiclong. La separación del punto caliente es similar a la reducción del tamaño de partícula de bloqueo en la operación bloqueada, separando un bloqueo en varias cerraduras para mejorar el rendimiento. En sin bloqueo, se pueden usar métodos similares para aumentar la tasa de éxito de CAS, mejorando así el rendimiento.
Esquema de longadder:
El método de implementación de AtomicLong es que hay una variable de valor en el interior. Cuando múltiples subprocesos son autodenominales y autodecrupados, todos se operan desde el nivel de instrucción de la máquina a través de instrucciones CAS para garantizar la atomicidad de la concurrencia. La única razón por la que restringe la eficiencia de Atomiclong es la alta concurrencia. La alta concurrencia significa que el CAS tiene una mayor probabilidad de falla, más tiempos de reintento y cuanto más hilos vuelvan a intentar, mayores son las posibilidades de falla de CAS, que se convierte en un círculo vicioso, y la eficiencia de Atomiclong se reduce.
Longadder dividirá un valor en varias celdas y sumará todas las celdas al valor. Por lo tanto, al sumar y restar la longadder, solo necesita operar en diferentes celdas. Diferentes hilos realizan operaciones CAS en diferentes celdas. Por supuesto, la tasa de éxito de CAS es alta (imagine 3+2+1 = 6, un hilo 3+1, el otro hilo 2+1, y finalmente 8, Longadder no tiene una API para la multiplicación y la división).
Sin embargo, cuando el número de concurrencia no es muy alto, dividirse en varias células también requiere mantener la célula y sumar, lo que no es tan eficiente como la implementación de Atomiclong. Longadder usó una forma inteligente de resolver este problema.
En la situación inicial, Longadder y Atomiclong son los mismos. Solo cuando CAS falla, el valor se dividirá en celdas. Cada vez que se realiza la falla, se incrementará el número de celdas. Esto también es eficiente en baja concurrencia. En alta concurrencia, este método de procesamiento "adaptativo" no fallará después de alcanzar un cierto número de células, y la eficiencia mejorará enormemente.
Longadder es una estrategia de intercambiar espacio por tiempo.
2. Completefuture
Implemente la interfaz de finalización de finalización (más de 40 métodos), la mayoría de los cuales se utilizan en la programación funcional. Y apoyar llamadas de transmisión
Completfuture es una versión mejorada de Future en Java 8
Implementación simple:
import java.util.concurrent.completableFuture; public class AskThread implementa Runnable {completeFuture <Integer> re = null; public askThread (completofuture <integer> re) {this.re = re; } @Override public void run () {int myre = 0; intente {myre = re.get () * re.get (); } catch (Exception e) {} System.out.println (myre); } public static void main (string [] args) lanza interruptedException {final completefuture <integer> futuro = new CompletableFuture <Integer> (); nuevo hilo (nuevo askthread (futuro)). start (); // simular un proceso de cálculo a largo plazo. // informar el resultado de finalización Future.complete (60); }} Lo más criticado del futuro es que tienes que esperar y verificar si la tarea ha sido completada por ti mismo. En el futuro, el tiempo para que la tarea se complete es incontrolable. La mayor mejora de CompleteFuture es que el tiempo para la finalización de la tarea también está abierto.
futuro.complete (60);
Se usa para establecer el tiempo de finalización.
Ejecución asincrónica de CompleteFuture:
public static entero calc (entero para) {try {// simula un hilo de ejecución largo.sleep (1000); } capt (interruptedException e) {} return para * para; } public static void main (string [] args) lanza interruptedException, ExecutionException {final CompletableFuture <Integer> Future = CompletableFuture .SupplyAsync (() -> Calc (50)); System.out.println (futuro.get ()); } Llamada de transmisión de CompletableFuture: public static entero calc (entero para) {try {// simula una ejecución larga thread.sleep (1000); } capt (interruptedException e) {} return para * para; } public static void main (string [] args) lanza interruptedException, ExecutionException {completableFuture <void> fu = completofuture .supplyAsync (() -> calc (50)) .ThenApply (((i) -> integer.ToString (i)) .ThenApply ((STR) -> "/" + ""/"/" ")") ")") ")") ")") ")") ")") .ThenAcept (System.out :: println); fu.get (); }Combine múltiples futas completables:
Public static entero calc (entero para) {return para / 2; } public static void main (string [] args) lanza interruptedException, ExecutionException {CompletableFuture <Void> FU = CompletableFuture .SupplyAsync (() -> calc (50)). "/" ") .ThenAcept (System.out :: println); fu.get (); } Estos ejemplos se centran más en algunas características nuevas de Java 8. Aquí hay algunos ejemplos para ilustrar las características, por lo que no entraré en profundidad.
CompleteFuture tiene poco que ver con el rendimiento, pero es más importante para apoyar la programación funcional y la mejora de las funciones. Por supuesto, la configuración del tiempo de finalización es lo más destacado.
3. Stampedlock
En el artículo anterior, se acaba de mencionar la separación de bloqueos, y la importante implementación de la separación de bloqueos es ReadWriteLock. Stampedlock es una mejora de ReadWriteLock. La diferencia entre Stampedlock y ReadWriteLock es que Stampedlock cree que Read no debe bloquear las escrituras, y Stampedlock cree que cuando la lectura y la escritura son mutuamente excluyentes, la lectura debe volver a leer, en lugar de no permitir que el hilo de escritura escriba. Este diseño resuelve el problema de escribir hambre de hilos al leer más y escribir menos.
Entonces Stampedlock es una mejora que tiende a escribir hilos.
Ejemplo de Stampedlock:
import java.util.concurrent.locks.stampedlock; Public Class Point {Private Double x, y; Private final Stampedlock SL = new Stampedlock (); Void Move (doble deltax, doble deltay) {// un método exclusivamente bloqueado sello largo = sl.writeLock (); intente {x += deltax; y += deltay; } finalmente {sl.unlockwrite (sello); }} Double DistanceFromorigin () {// Un método de solo lectura Long Stamp = SL.TryPtimisticread (); doble currentx = x, currenty = y; if (! sl.validate (sello)) {sell = sl.readlock (); intente {currentx = x; actualy = y; } finalmente {sl.unlockread (sello); }} return math.sqrt (currentx * currentx + currenty * currenty); }}El código anterior simula el hilo de escritura y el hilo de lectura. Stampedlock verifica si es mutuamente excluyente según el sello. Al escribir un sello una vez, aumenta un cierto valor.
tryoptimisticread ()
Es la situación en la que la lectura y la escritura no son mutuamente excluyentes como se mencionó.
Cada vez que leas un hilo, primero hará un juicio
if (! sl.validate (sello))
En Validate, primero verificará si hay una redacción de subprocesos de escritura y luego determinará si el valor de entrada es el mismo que el sello actual, es decir, determinar si el hilo de lectura leerá los últimos datos.
Si hay una escritura de hilo de escritura, o el valor del sello es diferente, la retorno falla.
Si el juicio falla, por supuesto, puede intentar leerlo repetidamente. En el código de ejemplo, no está permitido intentar leerlo repetidamente, sino que usa el bloqueo de optimismo para degenerarse en los bloqueos de lectura ordinarios para leerlo. Esta situación es un método de lectura pesimista.
sello = sl.readlock ();
Idea de implementación de Stampedlock:
CLH BLOK SPIN: Cuando falla la aplicación de bloqueo, el hilo de lectura no se suspenderá de inmediato. Se mantendrá una cola de hilo de espera en la cerradura. Todos los hilos que se aplican para cerraduras, pero no se registran hilos exitosos en esta cola. Cada nodo (un nodo representa un hilo) guarda un bit bloqueado para determinar si el hilo actual ha liberado el bloqueo. Cuando un hilo intenta adquirir un bloqueo, obtiene el nodo de cola de la cola de espera actual como su nodo predecesor. Y use códigos como los siguientes para determinar si el nodo preámado ha lanzado con éxito el bloqueo
while (predslocked) {
}
Este bucle es esperar a que el nodo anterior libere el bloqueo, de modo que el hilo actual no sea suspendido por el sistema operativo, mejorando así el rendimiento.
Por supuesto, no habrá giros interminables, y el hilo se suspenderá después de varios giros.