En este capítulo, presentaremos palabras clave sincronizadas. El contenido involucrado incluye:
1. Principio sincronizado
2. Reglas básicas sincronizadas
3. Método sincronizado y bloque de código sincronizado
4. Bloqueo de instancia y bloqueo global
1. Principio sincronizado
En Java, cada objeto tiene y solo tiene un bloqueo de sincronización. Esto también significa que el bloqueo de sincronización existe en el objeto.
Cuando llamamos el método sincronizado de un objeto, adquirimos el bloqueo de sincronización del objeto. Por ejemplo, Sincronized (OBJ) adquiere el bloqueo de sincronización del "objeto OBJ".
El acceso a los bloqueos de sincronización por diferentes hilos es mutuamente excluyente. ¡En otras palabras, en cierto punto en el tiempo, el bloqueo de sincronización del objeto solo se puede obtener mediante un hilo! A través de bloqueos de sincronización, podemos lograr un acceso mutuamente excluyente a "objetos/métodos" en múltiples hilos. Por ejemplo, ahora hay dos hilos A y Hilt B, que acceden al "bloqueo sincrónico de Obj OBJ". Supongamos que en algún momento, el hilo A adquiere el "bloqueo de sincronización de OBJ" y realiza algunas operaciones; B solo puede obtener el "bloqueo de sincronización de OBJ" hasta que el hilo A libera el "bloqueo sincrónico de este objeto" y solo puede ejecutarse.
2. Reglas básicas sincronizadas
Resumimos las reglas básicas de sincronizado en los siguientes 3 e ilustramos a través de ejemplos.
Artículo 1: Cuando un hilo accede al "método sincronizado" o "bloque de código sincronizado" de "un cierto objeto", otros subprocesos se bloquearán desde el acceso al "método sincronizado" o "bloque de código sincronizado" de "el objeto".
Artículo 2: Cuando un hilo accede al "método sincronizado" o "bloque de código sincronizado" de "un cierto objeto", otros subprocesos aún pueden acceder al bloque de código asincronizado de "este objeto".
Artículo 3: Cuando un hilo accede al "método sincronizado" o "bloque de código sincronizado" de "un cierto objeto", se bloquearán otros hilos para acceder a otros "métodos sincronizados" o "bloque de código sincronizado" de "el objeto".
Artículo 1
Cuando un hilo accede al "método sincronizado" o "bloque de código sincronizado" de "un cierto objeto", otros hilos se bloquearán desde el acceso al "método sincronizado" o "bloque de código sincronizado" de "el objeto".
A continuación se muestra el programa de demostración correspondiente al "bloque de código sincronizado".
La copia del código es la siguiente:
clase Myrunable Implements Runnable {
@Anular
public void run () {
sincronizado (esto) {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName () + "bucle" + i);
}
} capt (interruptedException es decir) {
}
}
}
}
clase pública demo1_1 {
public static void main (string [] args) {
Runnable demo = new Myrunable ();
Hilo t1 = nuevo hilo (demo, "t1");
Hilo t2 = nuevo hilo (demostración, "t2");
t1.start ();
t2.start ();
}
}
Resultados de ejecución:
La copia del código es la siguiente:
bucle t1 0
bucle t1 1
T1 Loop 2
T1 Loop 3
T1 Loop 4
T2 Loop 0
T2 Loop 1
T2 Loop 2
T2 Loop 3
T2 Loop 4
Descripción de los resultados:
Hay un "bloque de código sincronizado (este)" en el método run (), y T1 y T2 son hilos creados en función del objeto Runnable "demo". Esto significa que podemos considerar esto sincronizado (esto) como "objeto de demostración ejecutable"; Por lo tanto, cuando se ejecuta un hilo, otro hilo debe esperar a que el "hilo en ejecución" libere el "bloqueo de sincronización de demostración" antes de que pueda ejecutarse.
Si confirma, descubrió este problema. Luego modificamos el código anterior y luego lo ejecutamos para ver cómo es el resultado y vemos si se confunde. El código fuente modificado es el siguiente:
La copia del código es la siguiente:
La clase mythread extiende el hilo {
public mythread (nombre de cadena) {
super (nombre);
}
@Anular
public void run () {
sincronizado (esto) {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName () + "bucle" + i);
}
} capt (interruptedException es decir) {
}
}
}
}
clase pública demo1_2 {
public static void main (string [] args) {
Hilo t1 = nuevo mythread ("t1");
Hilo t2 = nuevo mythread ("t2");
t1.start ();
t2.start ();
}
}
Descripción del código:
Comparando Demo1_2 y Demo1_1, descubrimos que la clase Mythread en Demo1_2 se hereda directamente del hilo, y T1 y T2 son hilos de niños mythread.
Afortunadamente, el método "run () de demo1_2" también llamado sincronizado (esto), al igual que el método "run () de demo1_1" también llamado sincronizado (esto).
Entonces, ¿el proceso de ejecución de Demo1_2 es el mismo que Demo1_1?
Resultados de ejecución:
La copia del código es la siguiente:
bucle t1 0
T2 Loop 0
bucle t1 1
T2 Loop 1
T1 Loop 2
T2 Loop 2
T1 Loop 3
T2 Loop 3
T1 Loop 4
T2 Loop 4
Descripción de los resultados:
Si este resultado no te sorprende en absoluto, entonces creo que tienes una comprensión más profunda de sincronizado y esto. De lo contrario, continúe leyendo el análisis aquí.
Esto sincronizado (esto) se refiere al "objeto de clase actual", es decir, el objeto actual correspondiente a la clase donde se encuentra sincronizado (esto). Su propósito es obtener el "bloqueo sincrónico del objeto actual".
Para Demo1_2, esto está sincronizado (esto) representa el objeto mythread, mientras que T1 y T2 son dos objetos de lectura diferente. Para el par demo1_1, esto sincronizado (esto) representa el objeto mirunable;
Artículo 2
Cuando un hilo accede al "método sincronizado" o "bloque de código sincronizado" de "un cierto objeto", otros hilos aún pueden acceder al bloque de código asincronizado de "este objeto".
A continuación se muestra el programa de demostración correspondiente al "bloque de código sincronizado".
La copia del código es la siguiente:
recuento de clases {
// Método que contiene bloque de sincronización sincronizado
public void synmethod () {
sincronizado (esto) {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName () + "Synmethod Loop" + i);
}
} capt (interruptedException es decir) {
}
}
}
// método asincrónico
public void nonynmethod () {
intentar {
para (int i = 0; i <5; i ++) {
Hilt.sleep (100);
System.out.println (Thread.CurrentThread (). GetName () + "Nonsynmethod Loop" + i);
}
} capt (interruptedException es decir) {
}
}
}
clase pública demo2 {
public static void main (string [] args) {
recuento final count = new Count ();
// Crear un nuevo T1, T1 llamará al método synmethod () del "objeto de conteo"
Hilo t1 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
count.synmethod ();
}
}, "t1");
// Crear un nuevo T2, T2 llamará al método noynmethod () del "Objeto de conteo"
Hilo t2 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
count.nonsynmethod ();
}
}, "T2");
t1.start ();
t2.start ();
}
}
Resultados de ejecución:
La copia del código es la siguiente:
T1 Synmetod Loop 0
T2 Nonsynmethod Loop 0
bucle de sinmetodo t1 1
T2 Nonsynmethod Loop 1
bucle de sinmetodo t1 2
T2 Nonsynmethod Loop 2
bucle de sinmetodo T1 3
T2 Nonsynmethod Loop 3
bucle de sinmetodo t1 4
T2 Nonsynmethod Loop 4
Descripción de los resultados:
Dos nuevos hilos infantiles T1 y T2 se crean en el hilo principal. T1 llamará al método Synmethod () del objeto de recuento, que contiene bloques de sincronización; Cuando T1 se está ejecutando, aunque se llama sincronizado (esto) para obtener el "bloqueo de sincronización de recuento";
Artículo 3
Cuando un hilo accede al "método sincronizado" o "bloque de código sincronizado" de "un cierto objeto", se bloqueará otros hilos a otros "métodos sincronizados" o "bloque de código sincronizado" del "objeto".
También modificaremos el cuerpo del método NonsynMethod () en el ejemplo anterior con sincronizado (esto). El código fuente modificado es el siguiente:
La copia del código es la siguiente:
recuento de clases {
// Método que contiene bloque de sincronización sincronizado
public void synmethod () {
sincronizado (esto) {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName () + "Synmethod Loop" + i);
}
} capt (interruptedException es decir) {
}
}
}
// también contiene método de bloque de sincronización sincronizado
public void nonynmethod () {
sincronizado (esto) {
intentar {
para (int i = 0; i <5; i ++) {
Hilt.sleep (100);
System.out.println (Thread.CurrentThread (). GetName () + "Nonsynmethod Loop" + i);
}
} capt (interruptedException es decir) {
}
}
}
}
clase pública demo3 {
public static void main (string [] args) {
recuento final count = new Count ();
// Crear un nuevo T1, T1 llamará al método synmethod () del "objeto de conteo"
Hilo t1 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
count.synmethod ();
}
}, "t1");
// Crear un nuevo T2, T2 llamará al método noynmethod () del "Objeto de conteo"
Hilo t2 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
count.nonsynmethod ();
}
}, "T2");
t1.start ();
t2.start ();
}
}
(Una vez) Resultado de ejecución:
La copia del código es la siguiente:
Synmethod (): 11
synblock (): 3
4. Bloqueo de instancia y bloqueo global
Bloqueo de instancia: bloqueado en un objeto de instancia. Si la clase es un singleton, entonces el bloqueo también tiene el concepto de un bloqueo global.
La palabra clave sincronizada corresponde al bloqueo de instancia.
Lock Global: esta cerradura está dirigida a una clase.
El bloqueo global corresponde a static sincronizado (o bloqueado en la clase o objeto de cargador de clase de esta clase).
Hay un ejemplo muy vívido de "bloqueo de instancia" y "bloqueo global":
La copia del código es la siguiente:
clase pulbica algo {
Public sincronizado void issynca () {}
Public sincronizado void isSyncb () {}
Public static sincronizado void csynca () {}
public static sincronizado void csyncb () {}
}
Supongamos que algo tiene dos instancias x e y. Analice las cerraduras adquiridas por los siguientes cuatro conjuntos de expresiones.
(01) x.issynca () y x.issyncb ()
(02) x.issynca () y y.issynca ()
(03) x.csynca () y y.csyncb ()
(04) x.issynca () y algo.csynca ()
(01) No se puede acceder simultáneamente. ¡Porque isSynca () e isSyncb () son bloqueos de sincronización que acceden al mismo objeto (objeto X)!
La copia del código es la siguiente:
// Código fuente de Locktest2.Java
clase algo {
Public sincronizado vacío issynca () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName ()+": isSynca");
}
} capt (interruptedException es decir) {
}
}
Public sincronizado vacío isSyncb () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName ()+": isSyncb");
}
} capt (interruptedException es decir) {
}
}
public static sincronizado void csynca () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csynca");
}
} capt (interruptedException es decir) {
}
}
public static sincronizado void csyncb () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csyncb");
}
} capt (interruptedException es decir) {
}
}
}
clase pública Locktest2 {
Algo x = nuevo algo ();
Algo y = nuevo algo ();
// Compare (02) x.issynca () con y.issynca ()
Private void test2 () {
// Crear un nuevo T21, y T21 llamará a X.issynca ()
Hilo t21 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
x.issynca ();
}
}, "T21");
// Crear un nuevo T22, y T22 llamará a X.ISSYNCB ()
Hilo t22 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
y.issynca ();
}
}, "T22");
T21.Start ();
T22.Start ();
}
public static void main (string [] args) {
LockTest2 demo = new LockTest2 ();
demo.test2 ();
}
}
Resultados de ejecución:
La copia del código es la siguiente:
T11: Issynca
T11: Issynca
T11: Issynca
T11: Issynca
T11: Issynca
T12: ISSYNCB
T12: ISSYNCB
T12: ISSYNCB
T12: ISSYNCB
T12: ISSYNCB
(02) se puede acceder al mismo tiempo. Debido a que no está accediendo al bloqueo de sincronización del mismo objeto, x.issynca () accede al bloqueo de sincronización de x, mientras que Y.issynca () accede al bloqueo de sincronización de y.
La copia del código es la siguiente:
// Código fuente de Locktest2.Java
clase algo {
Public sincronizado vacío issynca () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName ()+": isSynca");
}
} capt (interruptedException es decir) {
}
}
Public sincronizado vacío isSyncb () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName ()+": isSyncb");
}
} capt (interruptedException es decir) {
}
}
public static sincronizado void csynca () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csynca");
}
} capt (interruptedException es decir) {
}
}
public static sincronizado void csyncb () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csyncb");
}
} capt (interruptedException es decir) {
}
}
}
clase pública Locktest2 {
Algo x = nuevo algo ();
Algo y = nuevo algo ();
// Compare (02) x.issynca () con y.issynca ()
Private void test2 () {
// Crear un nuevo T21, y T21 llamará a X.issynca ()
Hilo t21 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
x.issynca ();
}
}, "T21");
// Crear un nuevo T22, y T22 llamará a X.ISSYNCB ()
Hilo t22 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
y.issynca ();
}
}, "T22");
T21.Start ();
T22.Start ();
}
public static void main (string [] args) {
LockTest2 demo = new LockTest2 ();
demo.test2 ();
}
}
Resultados de ejecución:
La copia del código es la siguiente:
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
(03) No se puede acceder simultáneamente. Debido a que csynca () y csyncb () son tipos estáticos, x.csynca () es equivalente a algo.issynca (), y y.csyncb () es equivalente a algo.issyncb (), por lo que comparten un bloqueo de sincronización y no pueden ser preguntado al mismo tiempo.
La copia del código es la siguiente:
// Código fuente de Locktest3.java
clase algo {
Public sincronizado vacío issynca () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName ()+": isSynca");
}
} capt (interruptedException es decir) {
}
}
Public sincronizado vacío isSyncb () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName ()+": isSyncb");
}
} capt (interruptedException es decir) {
}
}
public static sincronizado void csynca () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csynca");
}
} capt (interruptedException es decir) {
}
}
public static sincronizado void csyncb () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csyncb");
}
} capt (interruptedException es decir) {
}
}
}
clase pública Locktest3 {
Algo x = nuevo algo ();
Algo y = nuevo algo ();
// Compare (03) x.csynca () con y.csyncb ()
Private void test3 () {
// Crear un nuevo T31, y T31 llamará a X.issynca ()
Hilo t31 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
x.csynca ();
}
}, "T31");
// Crear un nuevo T32, y T32 llamará a X.ISSYNCB ()
Hilo t32 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
y.csyncb ();
}
}, "T32");
T31.Start ();
T32.Start ();
}
public static void main (string [] args) {
LockTest3 demo = nuevo LockTest3 ();
demo.test3 ();
}
}
Resultados de ejecución:
La copia del código es la siguiente:
T31: Csynca
T31: Csynca
T31: Csynca
T31: Csynca
T31: Csynca
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
(04) se puede acceder simultáneamente. Debido a que IsSynca () es un método de instancia, X.issynca () usa el bloqueo del objeto X; Por lo tanto, se puede acceder simultáneamente.
La copia del código es la siguiente:
// Código fuente de Locktest4.Java
clase algo {
Public sincronizado vacío issynca () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName ()+": isSynca");
}
} capt (interruptedException es decir) {
}
}
Public sincronizado vacío isSyncb () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (Thread.CurrentThread (). GetName ()+": isSyncb");
}
} capt (interruptedException es decir) {
}
}
public static sincronizado void csynca () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csynca");
}
} capt (interruptedException es decir) {
}
}
public static sincronizado void csyncb () {
intentar {
para (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csyncb");
}
} capt (interruptedException es decir) {
}
}
}
clase pública Locktest4 {
Algo x = nuevo algo ();
Algo y = nuevo algo ();
// Compare (04) x.issynca () con algo.csynca ()
Private void test4 () {
// Crear un nuevo T41, y T41 llamará a X.issynca ()
Hilo t41 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
x.issynca ();
}
}, "T41");
// Crear un nuevo T42, y T42 llamará a X.ISSYNCB ()
Hilo t42 = nuevo hilo (
nuevo runnable () {
@Anular
public void run () {
Algo.csynca ();
}
}, "T42");
T41.Start ();
t42.start ();
}
public static void main (string [] args) {
LockTest4 demo = nuevo LockTest4 ();
demo.test4 ();
}
}
Resultados de ejecución:
La copia del código es la siguiente:
T41: Issynca
T42: Csynca
T41: Issynca
T42: Csynca
T41: Issynca
T42: Csynca
T41: Issynca
T42: Csynca
T41: Issynca
T42: Csynca