En la programación multiproceso, el problema más crítico y más preocupado debería ser el problema de sincronización, que es un punto difícil y el núcleo.
Desde el sincronizado y volátil de la versión más temprana de JDK, hasta la interfaz de bloqueo en el paquete java.util.concurrent.locks proporcionado en JDK 1.5 (las implementaciones incluyen Readlock, WriteLock y Reentrantlock), la implementación múltiple también está madurando gradualmente.
¿Qué mecanismo se usa para controlar la sincronización? La primera reacción es el bloqueo, que debería haberse expuesto al aprender el sistema operativo y la base de datos. En los programas de Java Multi-Thread, cuando múltiples programas compiten por el mismo recurso, para evitar la corrosión de los recursos, al primer hilo que accede al recurso se le asigna un bloqueo de objeto, y las generaciones posteriores deben esperar la liberación de este bloqueo de objeto.
Sí, lo más preocupado sobre la sincronización de los hilos Java es el uso de recursos compartidos.
Primero comprendamos algunos recursos compartidos de los hilos disponibles.
Del JVM, necesitamos coordinar los datos compartidos por los hilos:
1. La variable de instancia guardada en el montón; 2. La variable de clase guardada en el área del método.
Cuando la máquina virtual Java carga una clase, cada objeto o clase estará asociado con un monitor para proteger la variable de instancia o la variable de clase del objeto; Por supuesto, si el objeto no tiene variables de instancia, o la clase no tiene variables, el monitor no monitoreará nada.
Para lograr el mutex de los monitores mencionados anteriormente, la máquina virtual asocia un bloqueo (también llamado bloqueo invisible) para cada objeto o clase. Permítanme explicar aquí que los bloqueos de clase también se implementan a través de bloqueos de objetos, porque cuando se carga la clase, el JVM creará una instancia de java.lang.class para cada clase; Entonces, cuando el bloqueo está en contra de un objeto, el objeto de clase de esta clase está bloqueado.
Además, un hilo puede bloquear un objeto varias veces, que corresponde a múltiples versiones; Es una calculadora de bloqueo proporcionada por JVM para cada bloqueo de objeto. El último bloqueo se agrega 1, y el menos 1 correspondiente, y cuando el valor de la calculadora es 0, se libera. El monitor usa este bloqueo de objeto dentro del JVM y también es generado automáticamente por el JVM. Todos los programadores no necesitan agregarlo por sí mismos.
Después de presentar el principio de sincronización de Java, llegaremos al tema y primero hablaremos sobre el uso de sincronizado. Otras sincronizaciones se introducirán en los siguientes capítulos.
Intentemos ejecutar un ejemplo primero.
paquete thread_test; / *** PRUEBA PROGRAMAS MULTITRADOS MULTITRADOS que extienden la implementación de la clase de hilo**/ public class TestThread extiende Thread {private int threadnum; public testthread (int threadnum) {this.threadnum = threadnum; } @Override public Synchronized void run () {for (int i = 0; i <1000; i ++) {system.out.println ("no." + Threadnum + ":" + i); }} public static void main (string [] args) arroja excepción {for (int i = 0; i <10; i ++) {new testThread (i) .Start (); Thread.sleep (1); }}}
Resultados de ejecución:
No.0: 887 No.0: 888 No.0: 889 No.0: 890 No.0: 891 No.0: 892 No.0: 893 No.0: 894 No.7: 122 No.7: 123 No.7: 124
Lo anterior es solo un clip, explicando un problema.
Si tiene cuidado, encontrará que No.0: 894 es seguido por No.7: 122, lo que significa que no comienza de 0 a 999.
Se dice que sincronizado puede implementar métodos de sincronización o bloques de sincronización, ¿por qué no puede funcionar aquí?
Primero analicemos el mecanismo de sincronización. La sincronización se logra a través del bloqueo. Entonces, en el ejemplo anterior, ¿qué objeto está bloqueado o qué clase está bloqueada? Hay dos variables en el interior, una es yo y la otra es Threadnum; Yo es interno al método, y Threadnum es privado.
Aprendamos sobre el mecanismo de ejecución de sincronizado:
En un programa Java, cuando se usa bloque sincronizado o método sincronizado, esta área está marcada para monitoreo; Mientras que cuando un JVM maneja el programa, cuando un programa ingresa al área de monitoreo, bloqueará automáticamente el objeto o clase.
Entonces, en el ejemplo anterior, ¿qué se bloquea después de que se usa la palabra clave sincronizada?
Cuando se sincronizó el método, bloquee el objeto de instancia que llama al método en sí como el bloqueo del objeto. En este ejemplo, los 10 hilos tienen sus propios objetos de clase TestThread, por lo que el bloqueo de objetos adquirido también es su propio bloqueo de objetos y no tiene nada que ver con otros hilos.
Para implementar el bloqueo de métodos, los objetos compartidos deben estar bloqueados.
Cambie el ejemplo anterior y luego eche un vistazo:
paquete thread_test; / *** PRUEBA PROGRAMAS MULTITRADOS MULTITRADOS que extienden la implementación de la clase de hilo**/ public class TestThread extiende Thread {private int threadnum; bandera de cadena privada; // Marque public testThread (int threadnum, string flag) {this.threadnum = threadnum; this.flag = flag; } @Override public void run () {SynChronized (Flag) {for (int i = 0; i <1000; i ++) {System.out.println ("no." + Threadnum + ":" + i); }}} public static void main (string [] args) lanza excepción {string flag = new String ("Flag"); para (int i = 0; i <10; i ++) {nuevo testThread (i, flag) .Start (); Thread.sleep (1); }}}
Esto también se agrega una bandera compartida. Luego, la bandera se sincroniza a través del bloque sincronizado; Esto cumple con las condiciones para bloquear el objeto compartido.
Sí, los resultados de la ejecución han llegado en orden.
A través del bloque sincronizado, especifique la adquisición de bloqueos de objetos para lograr la sincronización. Entonces, ¿hay otros métodos que puedan implementarse a través del método sincronizado?
De acuerdo con el principio de sincronización: si se puede obtener un bloqueo de objeto o bloqueo de clase compartido, se puede lograr la sincronización. Entonces, ¿podemos lograrlo compartiendo un bloqueo de clase?
Sí, podemos usar métodos de sincronización estática. De acuerdo con las características de los métodos estáticos, solo permite que se llame al objeto de clase en sí mismo, y no puede llamarse instanciando un objeto de clase. Luego, si obtiene el bloqueo de este método estático, obtendrá el bloqueo de clase, y este bloqueo de clase es todos los bloqueos de clase TestThread, y se logra el propósito de obtener los bloqueos de clase compartidos.
El código de implementación es el siguiente:
paquete thread_test; / ** * Pruebe programas múltiples de subprocesos que extienden la implementación de la clase de hilos * * @author ciding * @createTime 7 de diciembre de 2011 9:37:25 am * */ public class testThread extiende Thread {private int threadnum; public testthread (int threadnum) {this.threadnum = threadnum; } public static sincronizado void stattictest (int threadnum) {for (int i = 0; i <1000; i ++) {system.out.println ("no." + threadnum + ":" + i); }} public static void main (string [] args) arroja excepción {for (int i = 0; i <10; i ++) {new testThread (i) .Start (); Thread.sleep (1); }} @Override public void run () {statictSt (threadnum); }} El resultado de ejecución se omite, lo mismo que en el segundo ejemplo.
El contenido anterior explica principalmente dos problemas: bloques de sincronización y métodos de sincronización.
1. Bloque sincronizado: el bloqueo del objeto adquirido es el bloqueo del objeto de indicador sincronizado (indicador).
2. Método de sincronización: el objeto de clase al que pertenece el método y el bloqueo de objeto de clase.
El método de sincronización estática definitivamente se sincronizará ya que se compartirán múltiples hilos.
En lugar de métodos de sincronización estática, solo se sincronizarán en modo singleton.