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
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); } } }
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.
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); }
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.
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); } }
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.
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); }
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
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 (); } } } }
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
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 (); } } } }
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
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"); } }
El resultado:
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
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
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"); } }
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
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"); } }
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.