análisis JDK8 del código fuente LockSupport

I. Introducción

  Inicialmente se propuso analizar ReentrantLock, pero en el análisis final, encontró que sin el apoyo de LockSuport, por lo que simplemente se inicia en el primer análisis LockSupport, porque es la base de la cerradura, el mecanismo de bloqueo es un proveedor de herramientas, por lo que primero sea análisis.

Dos, código fuente LockSupport análisis

  2.1 propiedades de la clase 

Copiar el código

LockSupport public class {
    // aplicación inalámbrica a través de las características intrínsecas de la API
    INSEGURA sun.misc.Unsafe private static final;
    // representa la dirección de desplazamiento de la memoria
    estática privada parkBlockerOffset tiempo final;
    // representa la dirección de desplazamiento de la memoria
    estática privada de semillas a largo final;
    // representa la dirección de desplazamiento de la memoria
    estática privada SONDA tiempo final;
    // representa la dirección de desplazamiento de la memoria
    private static final larga secundaria;
    
    estática {
        tratar {
            // obtener ejemplos inseguros
            UNSAFE = sun.misc.Unsafe.getUnsafe ();
            // Tipo de clase Thread
            Clase tk = Thread.class <?>;
            // Obtener la dirección de desplazamiento de la memoria de campo parkBlocker de hilo
            parkBlockerOffset = UNSAFE.objectFieldOffset
                (Tk.getDeclaredField ( "parkBlocker"));
            // obtener la dirección de desplazamiento de la memoria threadLocalRandomSeed campo de hilo
            SEED = UNSAFE.objectFieldOffset
                (Tk.getDeclaredField ( "threadLocalRandomSeed"));
            // Obtener la dirección de desplazamiento de la memoria de campo threadLocalRandomProbe de hilo
            SONDA = UNSAFE.objectFieldOffset
                (Tk.getDeclaredField ( "threadLocalRandomProbe"));
            // obtener la dirección de desplazamiento de la memoria threadLocalRandomSecondarySeed campo de hilo
            SECUNDARIA = UNSAFE.objectFieldOffset
                (Tk.getDeclaredField ( "threadLocalRandomSecondarySeed"));
        } Catch (Exception ex) {throw new Error (ex); }
    }
}

Copiar el código

  Descripción: Campo de INSEGURA representa la clase sun.misc.Unsafe, ver su fuente, haga clic aquí , el programa general no permite llamadas directas, y los programas de campo de tipo durante mucho tiempo un ejemplo de un objeto corrector correspondiente dirección en la memoria puede ser compensado por la Obtiene o establece el valor del campo de dirección.

  constructor 2,2 clase 

// constructor privado no puede ser instanciada
LockSupport privada () {}

  Descripción: LockSupport solamente un constructor privado no se pueden crear instancias.

  2.3 El análisis de la función núcleo

  Antes de función de análisis LockSupport, introducida primera clase sun.misc.Unsafe parque y la función Unpark, debido a que las funciones básicas se basan LockSupport parque y funciones no seguras desaparcar definidos en la clase, definen dos funciones es la siguiente.  

parque público nativa vacío (isAbsolute booleano, mucho tiempo);
pública Unpark native void (hilo de rosca);

  Descripción: La descripción de las siguientes dos funciones

  ① función de parque, bloqueando el hilo y el hilo antes de que se bloqueó el suceso siguiente: ① llamar a la función de anular el estacionamiento, el permiso para liberar el hilo. ② El hilo se interrumpe. Para ③ tiempo establecido. Y, cuando el tiempo es el tiempo absoluto, isAbsolute es cierto, de lo contrario, isAbsolute es falsa. Cuando el tiempo es 0 indica una espera infinita hasta anular el estacionamiento se produzca.

  ② función de anular el estacionamiento, el permiso para liberar el hilo, después del parque bloqueado hilo que se activa llamadas. Esta función no es segura, esta función se llama para asegurarse de que el hilo sigue vivo.

  1. Función de parque 

  la función de sobrecarga parque tiene dos versiones, el método se resume a continuación  

public static parque vacío ();
public static parque vacío (bloqueador de objetos);

  Explicación: La diferencia entre las dos funciones es que la función Park () no bloqueante, es decir, el hilo no se proporciona campo parkBlocker. funciones parque (Objeto) escriba lo siguiente.

Copiar el código

public static parque vacío (bloqueador de Object) {
        // obtener el subproceso actual
        Thread t = Thread.currentThread ();
        // establecer Bloqueador
        setBlocker (t, bloqueador);
        // obtener licencia
        UNSAFE.park (falso, 0L);
        // volver a ejecutar después de este valor Bloqueador
        setBlocker (t, null);
    }

Copiar el código

  Descripción: Cuando se llama a la función parque, primero obtener el subproceso actual, y después fijar campo parkBlocker hilo actual que la función de llamadas setBlocker, después de llamar a la clase inseguro función de parque, la función setBlocker después de entonces llamada. Entonces la pregunta es, ¿por qué esta función parque que se llamará la función setBlocker dos veces? La razón es simple, cuando se llama a la función parque, el campo parkBlocker primer conjunto hilo actual, y luego llama insegura la función parque, después de lo cual el hilo actual ha sido bloqueado, esperando función de anular el estacionamiento de la rosca se llama, por lo que la parte posterior de una función setBlocker no se puede ejecutar, la función de anular el estacionamiento se llama, después de la autorización de rosca, puede seguir circulando, se ejecutará la segunda setBlocker, el campo parkBlocker a la rosca es nulo, completando así todo el parque funciones lógicas. Si no hay una segunda setBlocker, a continuación, después de que ningún aparcamiento de llamadas (bloqueador de objetos), y llamadas directas función getBlocker, o conseguir un bloqueador antes del parque (bloqueador de objetos) conjunto obviamente ilógico. En resumen, hay que asegurarse de que todo el parque función (bloqueador de objetos) después de la aplicación del campo parkBlocker mensaje ha vuelto a nulo. Por lo tanto, la función del parque (Objeto) Tipo de setBlocker debe llamar a la función dos veces. setBlocker sigue. 

estática privada setBlocker vacío (Tema t, arg Object) {
        // Establecer el hilo t arg valor del campo parkBlocker
        UNSAFE.putObject (t, parkBlockerOffset, arg);
    }

  Descripción: Este método establece el hilo t campo parkBlocker es arg.

  Otra versión sobrecargada sin parámetros, la función del parque () es la siguiente.  

public static parque void () {
    // obtener una licencia, el tiempo es infinito, hasta que pueda obtener licencias
        UNSAFE.park (falso, 0L);
}

  Descripción: Después de llamar a la función del parque se desactiva cuando el hilo actual, a menos que el permiso está disponible. Antes de que ocurra una de las tres cosas, el subproceso actual estará en un estado latente, es decir, cuando se producen las siguientes condiciones, el hilo actual será obtener una licencia, que puede seguir funcionando.

  ① Algunos otro hilo el hilo actual como el Unpark invocación de destino.

  ② Algunas otras interrupciones enhebrar el hilo actual.

  ③ La llamada falsamente (es decir, sin ningún motivo) devuelve.

  2. Función parkNanos

  Esta función desactiva el permiso de hilo actual está disponible, con capacidad para el tiempo de espera especificado. Las funciones específicas de la siguiente manera.

Copiar el código

estático public void parkNanos (bloqueador de objetos, nanos largos) {
        if (nanos> 0) {// el tiempo es mayor que 0
            // obtener el subproceso actual
            Thread t = Thread.currentThread ();
            // establecer Bloqueador
            setBlocker (t, bloqueador);
            // obtener una licencia y el tiempo de configuración
            UNSAFE.park (falso, nanos);
            // conjunto de permisos
            setBlocker (t, null);
        }
    }

Copiar el código

  Descripción: Esta función se denomina función setBlocker dos veces, nanos parámetro representa el tiempo relativo indica el tiempo de espera.

  3. Función parkUntil

  Esta función desactiva el subproceso actual hasta la fecha límite especificado, a menos que el permiso está disponible. Las funciones específicas de la siguiente manera.  

Copiar el código

estático public void parkUntil (bloqueador de objeto, a largo plazo) {
        // obtener el subproceso actual
        Thread t = Thread.currentThread ();
        // establecer Bloqueador
        setBlocker (t, bloqueador);
        UNSAFE.park (true, plazo);
        // set NULL Bloqueador
        setBlocker (t, null);
    }

Copiar el código

  Descripción: Esta función también se llama función setBlocker dos veces, parámetro plazo representa el tiempo absoluto, representa el tiempo especificado.

  4. función de anular el estacionamiento

  Esta función significa que si la licencia subproceso dado no está disponible, a continuación, haga disponible. Si el hilo se bloquea en el parque entonces será desbloquear estado. De lo contrario, la siguiente llamada a parque no se garantiza el bloqueo. Si no se ha iniciado subproceso dado, no puede garantizar que esta operación no tiene efecto. Las funciones específicas de la siguiente manera.  

public static anular el estacionamiento vacío (hilo de rosca) {
        si (rosca! = null) // hilo no está vacía
            UNSAFE.unpark (rosca); // liberar la licencia hilo
    }

  Explicación: La licencia de liberación, hilo designado puede continuar funcionando.

En tercer lugar, el ejemplo muestra

  3,1 para lograr dos sincronización de subprocesos

  1. wait / notify implementado  

Copiar el código

com.hust.grid.leesf.locksupport empaquetar;

MyThread clase extends Thread {
    
    public void run () {
        sincronizado (este) {
            System.out.println ( "antes de notificar");            
            notificar();
            System.out.println ( "después de notificar");    
        }
    }
}

public class {WaitAndNotifyDemo
    public static void Main (args String []) {lanza InterruptedException
        MyThread miThread = nuevo MyThread ();            
        sincronizado (miThread) {
            tratar {        
                myThread.start ();
                // principales 3s sueño hilo
                Thread.sleep (3000);
                System.out.println ( "antes de espera");
                // bloquear el hilo principal
                myThread.wait ();
                System.out.println ( "después de espera");
            } Catch (InterruptedException e) {
                e.printStackTrace ();
            }            
        }        
    }
}

Copiar el código

  Los resultados operativos 

antes de espera
antes de notificar
después de notificar
después de esperar

  Descripción: El diagrama de flujo de la específica

  

  Cuando se utiliza de espera / notificar a la sincronización, primero debe esperar la llamada, después de llamar a notificar, si la primera llamada notificar, a continuación, espera de llamadas, a ningún efecto. código específico de la siguiente  

Copiar el código

com.hust.grid.leesf.locksupport empaquetar;

MyThread clase extends Thread {
    public void run () {
        sincronizado (este) {
            System.out.println ( "antes de notificar");            
            notificar();
            System.out.println ( "después de notificar");    
        }
    }
}

public class {WaitAndNotifyDemo
    public static void Main (args String []) {lanza InterruptedException
        MyThread miThread = nuevo MyThread ();        
        myThread.start ();
        // principales 3s sueño hilo
        Thread.sleep (3000);
        sincronizado (miThread) {
            tratar {        
                System.out.println ( "antes de espera");
                // bloquear el hilo principal
                myThread.wait ();
                System.out.println ( "después de espera");
            } Catch (InterruptedException e) {
                e.printStackTrace ();
            }            
        }        
    }
}

Copiar el código

  El resultado:  

antes de notificar
después de notificar
antes de espera

  Descripción: Como la primera llamada notificar, a continuación, llamar a la espera, esta vez el hilo principal será siempre permanecerá bloqueada.

  3.2 / parque de lograr UNPARK 

Copiar el código

com.hust.grid.leesf.entry empaquetar;

java.util.concurrent.locks.LockSupport importación;

MyThread clase extends Thread {
    Objeto objeto privada;

    MyThread pública (objeto Object) {
        this.object = objeto;
    }

    public void run () {
        System.out.println ( "antes Unpark");
        tratar {
            Thread.sleep (1000);
        } Catch (InterruptedException e) {
            e.printStackTrace ();
        }
        // obtener bloqueador
        System.out.println ( "información Blocker" + LockSupport.getBlocker ((Tema) objeto));
        // licencia de liberación
        LockSupport.unpark ((Thread) objeto);
        // 500 ms del sueño, para asegurar la ejecución de la setBlocker parque (t, null);
        tratar {
            Thread.sleep (500);
        } Catch (InterruptedException e) {
            e.printStackTrace ();
        }
        // Obtener bloqueador de nuevo
        System.out.println ( "información Blocker" + LockSupport.getBlocker ((Tema) objeto));

        System.out.println ( "después de Unpark");
    }
}

public class Test {
    public static void Main (args String []) {
        MyThread miThread = nuevo MyThread (Thread.currentThread ());
        myThread.start ();
        System.out.println ( "antes del parque");
        // obtener licencia
        LockSupport.park ( "ParkAndUnparkDemo");
        System.out.println ( "después del parque");
    }
}

Copiar el código

  El resultado:  

Copiar el código

antes del parque
antes de anular el estacionamiento
información bloqueador ParkAndUnparkDemo
después de parque
información bloqueador nula
después de anular el estacionamiento

Copiar el código

  Descripción: Este programa primer parque ejecución, y luego ejecutar anular el estacionamiento, la sincronización, y antes y después de anular el estacionamiento son llamados getBlocker, se puede ver los resultados de los dos no son los mismos, y los resultados de la segunda llamada es nula, esto se debe después de una llamada a Unpark, realizado función Lock.park (bloqueador de Object) en setBlocker (t, null) funciones, así que cuando la llamada es nulo segundo getBlocker.

  El ejemplo es llamar al parque, a continuación, llamar a anular el estacionamiento, ahora modificar el programa, primero anular el estacionamiento de llamada, a continuación, llamar parque, ver si se puede sincronizar correctamente. código específico de la siguiente  

Copiar el código

com.hust.grid.leesf.locksupport empaquetar;

java.util.concurrent.locks.LockSupport importación;

MyThread clase extends Thread {
    Objeto objeto privada;

    MyThread pública (objeto Object) {
        this.object = objeto;
    }

    public void run () {
        System.out.println ( "antes Unpark");        
        // licencia de liberación
        LockSupport.unpark ((Thread) objeto);
        System.out.println ( "después de Unpark");
    }
}

public class {ParkAndUnparkDemo
    public static void Main (args String []) {
        MyThread miThread = nuevo MyThread (Thread.currentThread ());
        myThread.start ();
        tratar {
            // principales 3s sueño hilo
            Thread.sleep (3000);
        } Catch (InterruptedException e) {
            e.printStackTrace ();
        }
        System.out.println ( "antes del parque");
        // obtener licencia
        LockSupport.park ( "ParkAndUnparkDemo");
        System.out.println ( "después del parque");
    }
}

Copiar el código

  El resultado:

antes de anular el estacionamiento
después de anular el estacionamiento
antes del parque
después de parque

  Nota: se puede ver, el anular el estacionamiento de llamada anterior, cuando el entonces estacionamiento de llamadas, siendo capaz de sincronizar adecuadamente, no se debe a la espera / notificación que llamar a la obstrucción causada por orden incorrecto. Así parque / anular el estacionamiento frente a la espera / notificar más flexible.

  2. La respuesta de interrupción

  Vea el ejemplo siguiente  

Copiar el código

com.hust.grid.leesf.locksupport empaquetar;

java.util.concurrent.locks.LockSupport importación;

MyThread clase extends Thread {
    Objeto objeto privada;

    MyThread pública (objeto Object) {
        this.object = objeto;
    }

    public void run () {
        System.out.println ( "antes de interrupción");        
        tratar {
            // 3s del sueño
            Thread.sleep (3000);
        } Catch (InterruptedException e) {
            e.printStackTrace ();
        }    
        hilo de rosca = (Tema) objeto;
        // hilo de interrupción
        thread.interrupt ();
        System.out.println ( "después de interrupción");
    }
}

public class {InterruptDemo
    public static void Main (args String []) {
        MyThread miThread = nuevo MyThread (Thread.currentThread ());
        myThread.start ();
        System.out.println ( "antes del parque");
        // obtener licencia
        LockSupport.park ( "ParkAndUnparkDemo");
        System.out.println ( "después del parque");
    }
}

Copiar el código

  El resultado: 

antes del parque
antes de interrupción
después de la interrupción
después de parque

  Nota: Se puede ver que en el hilo principal llama el parque bloqueada, emitido la señal de interrupción hilo miThread, el hilo principal seguirá funcionando en este momento, que es clara en este momento de interrupción de la función anular el estacionamiento de la misma.

IV Resumen

  LockSupport para la creación de cerraduras y otras primitivas de bloqueo de la clase básica de sincronización de subprocesos. En resumen, cuando se llama LockSupport.park, indica que el hilo actual esperará hasta que una licencia al llamar LockSupport.unpark, el hilo debe esperar el permiso para ser pasado como parámetro, por lo que este hilo sigue funcionando.

Publicados 361 artículos originales · ganado elogios 370 · vistas 270 000 +

Supongo que te gusta

Origin blog.csdn.net/qq_33589510/article/details/104740390
Recomendado
Clasificación