Antes de Java 5, se usó la palabra clave sincronizada para implementar la función de bloqueo.
La palabra clave sincronizada se puede usar como un modificador (método sincronizado) o como una declaración dentro de una función (bloque de código sincronizado).
Para dominar sincronizado, la clave es dominar el uso de esa cosa como bloqueo. Para los métodos no estáticos (métodos miembros) de una clase, significa obtener el bloqueo de la instancia del objeto; Para los métodos estáticos (métodos de clase) de una clase, es necesario obtener el bloqueo del objeto de clase; Para los bloques de código síncronos, es necesario especificar qué bloqueo del objeto se obtiene. Los métodos no estáticos sincronizados pueden considerarse como un bloque de código sincronizado (este) {...} que contiene todo el método.
Ya sea que se trate de un bloque de código sincrónico o un método de sincronización, solo un hilo puede ingresar a la vez (como máximo, un subproceso ejecuta el segmento de código al mismo tiempo), y si otros hilos intentan ingresar (ya sea el mismo bloque sincrónico o un bloque de sincronización diferente), JVM los colgará (ponte en el grupo de bloqueo de espera). Esta estructura se llama sección crítica en la teoría de la concurrencia.
En JVM, para mejorar la eficiencia, cada hilo que se ejecuta al mismo tiempo tendrá una copia de caché de los datos que está procesando. Cuando usamos sincronzied para la sincronización, lo que realmente está sincronizado es el bloque de memoria que representa el objeto bloqueado en diferentes subprocesos (los datos de copia permanecerán sincronizados con la memoria principal. Ahora sabemos por qué se usa la sincronización de palabras). En pocas palabras, después de ejecutar el bloque de sincronización o el método de sincronización, cualquier modificación realizada al objeto bloqueado debe escribirse nuevamente a la memoria principal antes de liberar el bloqueo; Después de ingresar el bloque de sincronización y obtener el bloqueo, los datos del objeto bloqueado se leen desde la memoria principal, y la copia de datos del hilo que contiene el bloqueo debe sincronizarse con la vista de datos en la memoria principal.
Los siguientes son ejemplos específicos para ilustrar las diversas situaciones de sincronizado.
Método de sincronización sincronizado
Primero, echemos un vistazo al ejemplo del método de sincronización:
Public Class SynChronizedTest1 extiende el hilo {privado sincronizado testSynchronizedMethod () {for (int i = 0; i <10; i ++) {System.out.println (thread.currentThread (). getName () + "testSyncronizedMethod:" + i); intente {thread.sleep (100); } catch (InterruptedException e) {E.PrintStackTrace (); }}} @Override public void run () {testSynchronizedMethod (); } public static void main (string [] args) {SynChronizedTest1 t = new SynChronizedTest1 (); t.Start (); t.testsynchronizedMethod (); }}Ejecutando las salidas del programa:
TestSynCronizedMethod principal: 0 TestSyncronizedMethod de TestSyCronized: 1 TestSyncronizedMethod de TestSyCronized: 2 TestSyncronizedMethod principal: 3 TestSyncronizedMethod principal: 4 TestSyncronizedMethod principal: 5 Principal TestSyncronizedMethod testSynCronizedMethod: 9 testSynCronizedMethod: 0 hilo-0 testSynCronizedMethod: 1 hilo-0 testSynChronizedMethod: 2 hilo-0 testSynChronizedMethod: 3 testSynChronizedMethod: 4 hilo-0 testSyChronizedMethod: 5 hilo testshronshronizedmethodmethod: 6 hilo de hilo: 4 hilo-0 testShronizedMethod: 5 hilo testshronshronizedmethodmethod: 6 hilo de hilo: 4 hilt-0 TestSynCronizedMethod: 7 TestSynChronizedMethod de testSyCronized: 8 TestSyncronizedMethod: 9
Puede ver que el método TestSynchronizedMethod se ejecuta sincrónicamente entre dos hilos.
Si el método principal se modifica a lo siguiente, los dos hilos no pueden ejecutarse sincrónicamente, porque el monitor de sincronización de los dos subprocesos no es el mismo objeto y no puede desempeñar un papel sincrónico.
public static void main (string [] args) {Thread t = new SynChronizedTest1 (); t.Start (); Thread t1 = new SynChronizedTest1 (); t1.start (); }El resultado de salida es el siguiente:
Thread-0 testSynCronizedMethod: 0 hilo-1 testSynChronizedMethod: 0 test-0 testSynChronizedMethod: 1 thread-1 testSynChronizedMethod: 1 testSynChronizedMethod: 2 testSynChronizedMethod: 2 hilo-0 testSynChronizedMethod: 3 hilo-1 testSyChronsEnthodmethod: 3 hilo de hilo: 3 hilo de hilo: 2 hilo-thifre-0 testSynCronizedMethod: 4 hilo-1 testSynCronizedMethod: 4 testSynCronizedMethod: 5 hilo-1 testSyncronizedMethod: 5 hilo-0 testSynChronizedMethod: 6 hilt-1 testSynchronizedMethod: 6 hilo-0 testsyncronizedMethod: 7 hilo-1 testSynchonizedmethod: 7 hilo de hilo-0 testsyncronizado testSyncronizedMethod: 8 hilo-1 testSyncronizedMethod: 8 hilo-0 testSyncronizedMethod: 9 test-1 testSyncronizedMethod: 9
Si el método principal modificado se puede ejecutar sincrónicamente entre dos hilos, el método TestSynCronizedMethod debe declararse como un método estático, de modo que los monitores de los dos hilos son el mismo objeto (objeto de clase) y se pueden ejecutar sincrónicamente. El código modificado se ve así:
Public Class SynChronizedTest1 extiende el hilo {privado sincronizado sincronizado testSynchronizedMethod () {for (int i = 0; i <10; i ++) {System.out.println (Thread.CurrentThread (). GetName () + "TestSynCronizedMethod:" + I); intente {thread.sleep (100); } catch (InterruptedException e) {E.PrintStackTrace (); }}} @Override public void run () {testSynchronizedMethod (); } public static void main (string [] args) {Thread t = new SynChronizedTest1 (); t.Start (); Thread t1 = new SynChronizedTest1 (); t1.start (); }}El resultado de salida es el siguiente:
Thread-0 testSynCronizedMethod: 0 testSynChronizedMethod: 1 testSynChronizedMethod: 2 testSynCronizedMethod: 3 testSynCronizedMethod: 4 testSynCronizedMethod de testSyCronizedmethod: 5 hilo-0 testSyCronizedMethod: 6 hilo de testSynchonizedmethonizedmethonizedmethonizado: 7 hilo: 7 hiltodmethod. testSynCronizedMethod: 8 hilo-0 testSynCronizedMethod: 9 hilo-1 testSynCronizedMethod: 0 hilo-1 testSynCronizedMethod: 1 hilo-1 testSynCronizedMethod: 2 hilo-1 testSynchronizedMethod: 3 hilo-1 testSynChronChronMethod: 4 hilo 1 testSynchronmethod: 5 hilo-1 testethethethethethethetHethethethethethethethethethethethetMeTmonTmonyMeTmonizado: testShonShod:: testShonShodmetmethon: testethonschonschonschonschonschonschonschonschonschonschonschonschonschonschonshods. testSyncronizedMethod: 7 hilo-1 testSyncronizedMethod: 8 hilo-1 testSyncronizedMethod: 9
La situación de los bloques sincrónicos es similar al método de sincronización, excepto que el bloque sincrónico reduce la granularidad del control de sincronización, lo que puede ejercer mejor la eficiencia de la ejecución paralela multi-subpase.
Use este objeto para controlar la sincronización entre las mismas instancias de objeto:
Public Class SynChronizedTest2 extiende el hilo {privado testSynChronizedBlock () {sincronizado (this) {for (int i = 0; i <10; i ++) {system.out.println (thread.currentThread (). getName () + "testSynchronizedblock:" + i);; intente {thread.sleep (100); } catch (InterruptedException e) {E.PrintStackTrace (); }}}} @Override public void run () {testSynChronizedBlock (); } public static void main (string [] args) {SynChronizedTest2 t = new SynChronizedTest2 (); t.Start (); T.TestSynchronizedBlock (); }}Resultado de salida:
Principal testSyncronizedBlock: 0 TestSynChronizedBlock principal: 1 TestSynChronizedBlock principal: 2 TestSynChronizedBlock principal: 3 TestSynChronizedBlock principal: 4 TestSynChronizedBlock principal: 5 TestSynChronizedBlock: 6 TestSynChronizedBlock principal: 7 TestSynchronizedBlock principal: 8 Principal TestSyChronizedBlock: 9 TestSynChronizedBlock: 9 Testizizado: 9 Testizizado: 9 TIEDLOCHOLEDES PRINCIPIETIZADO: 9 TIEMBLOCHO: 9 TIEDLOCHONIZADO PAIN-9 TIEDLOCHOLEDES PRINCIPIETIZADO. testSynchronizedBlock:0 Thread-0 testSynchronizedBlock:1 Thread-0 testSynchronizedBlock:2 Thread-0 testSynchronizedBlock:3 Thread-0 testSynchronizedBlock:4 Thread-0 testSynchronizedBlock:5 Thread-0 testSynchronizedBlock:6 Thread-0 testSynchronizedBlock:7 Thread-0 testSynchronizedBlock:8 Thread-0 testSynchronizedblock: 9
Use objetos de clase para controlar la sincronización entre diferentes instancias:
Public Class SynChronizedTest2 extiende el hilo {private void testSynChronizedBlock () {SynChronized (SynChronizedTest2.Class) {for (int i = 0; i <10; i ++) {System.out.println (Thread.CurrentThread (). intente {thread.sleep (100); } catch (InterruptedException e) {E.PrintStackTrace (); }}}} @Override public void run () {testSynChronizedBlock (); } public static void main (string [] args) {Thread t = new SynChronizedTest2 (); t.Start (); Hilo t2 = new SynChronizedTest2 (); t2.start (); }}Resultado de salida:
Thread-0 testSynchronizedBlock:0 Thread-0 testSynchronizedBlock:1 Thread-0 testSynchronizedBlock:2 Thread-0 testSynchronizedBlock:3 Thread-0 testSynchronizedBlock:4 Thread-0 testSynchronizedBlock:5 Thread-0 testSynchronizedBlock:6 Thread-0 testSynchronizedBlock:7 Thread-0 testSynchronizedBlock:8 Thread-0 testSynCronizedBlock: 9 testSynChronizedBlock: 0 hilo-1 testSynChronizedBlock: 1 Thread-1 testSynChronizedBlock: 2 Thread-1 testSynChronizedBlock: 3 Thread-1 testSynChronizedBlock: 4 testSynChronizedBlock: 5 hilo-1 testSynchronizedBlock: 6 hilo-1 testschronizedBlock: 7 hilo 1 hilo 1 hilo 1 testSynchronizedBlock: 8 hilo-1 testSynchronizedblock: 9
Al usar la palabra clave sincronizada para el control de sincronización, debe comprender el monitor de objeto. Solo el proceso que obtiene el monitor puede ejecutarse, y todo lo demás debe esperarse para obtener el monitor. Cualquier objeto no nulo se puede usar como monitor de objeto. Cuando el sincronizado actúa sobre un método, la instancia del objeto está bloqueada; Al actuar en un método estático, la instancia del objeto se bloquea correspondiente al objeto.
Método síncrono para dos hilos para acceder a un objeto al mismo tiempo
Cuando dos hilos concurrentes acceden al método sincrónico del mismo objeto, solo se puede ejecutar un hilo. Otro hilo debe esperar a que el hilo actual ejecute esto antes de que pueda ejecutarse.
public class twothread {public static void main (string [] args) {final twothread twothread = new twothread (); Thread t1 = new Thread (new runnable () {public void run () {twothread.syncmethod ();}}, "a"); Thread t2 = new Thread (new runnable () {public void run () {twothread.syncmethod ();}}, "b"); t1.start (); t2.start (); } public sincronizado sincmethod () {for (int i = 0; i <5; i ++) {System.out.println (Thread.CurrentThread (). getName () + ":" + i); intente {thread.sleep (500); } capt (interruptedException es decir) {}}}}Resultado de salida:
A: 0a: 1a: 2a: 3a: 4b: 0b: 1b: 2b: 3b: 4
Dos hilos accede al método de sincronización de dos objetos
En este caso, sincronizado no funciona, al igual que el método ordinario. Porque los bloqueos correspondientes son sus objetos respectivos.
public class dosObject {public static void main (string [] args) {final dosObject Object1 = new TwoObject (); Thread t1 = new Thread (new runnable () {public void run () {object1.syncmethod ();}}, "object1"); t1.start (); final twoObject Object2 = new TwoObject (); Thread t2 = new Thread (new runnable () {public void run () {public void run () {object2.syncmethod ();}}, "object2"); t2.start (); } public sincronizado sincmethod () {for (int i = 0; i <5; i ++) {System.out.println (Thread.CurrentThread (). getName () + ":" + i); intente {thread.sleep (500); } capt (interruptedException es decir) {}}}}Una de las salidas posibles:
Object2: 0Object1: 0Object1: 1Object2: 1Object2: 2Object1: 2Object2: 3Object1: 3Object1: 4Object2: 4
Los dos hilos acceden al método estático sincronizado
En este caso, dado que la clase está bloqueada, en cualquier momento, solo un hilo puede ejecutar el método estático.
Acceso a métodos sincrónicos y métodos asincrónicos simultáneamente cuando un hilo accede a un método de sincronización de un objeto, otro hilo aún puede acceder a los métodos asincrónicos en ese objeto.
clase pública Syncandnosync {public static void main (String [] args) {final Syncandnosync syncandnosync = new Syncandnosync (); Thread t1 = new Thread (new runnable () {public void run () {syncandnosync.syncmethod ();}}, "a"); t1.start (); Thread t2 = new Thread (new runnable () {public void run () {syncandnosync.nosyncmethod ();}}, "b"); t2.start (); } public sincronizado void sincmethod () {for (int i = 0; i <5; i ++) {System.out.println (Thread.CurrentThread (). getName () + "at syncMethod ():" + i); intente {thread.sleep (500); } capt (interruptedException IE) {}}} public void nosyncMethod () {for (int i = 0; i <5; i ++) {System.out.println (thread.currentThread (). getName () + "en nosyncMethod ():" + i); intente {thread.sleep (500); } capt (interruptedException es decir) {}}}}Una posible salida:
B en nosyncMethod (): 0a en syncMethod (): 0b en nosyncMethod (): 1a en syncMethod (): 1b at nosyncMethod (): 2a en syncMethod (): 2b en nosyncmethod (): 3a en sincmethod (): 3a en syncmethod () nosyncMethod (): 4
Diferentes métodos de sincronización para acceder al mismo objeto
Cuando un hilo accede al método de sincronización A de un objeto, se bloqueará otros hilos de acceso a todos los demás métodos de sincronización en el objeto. Debido a que el primer hilo ha obtenido el bloqueo del objeto y otros roscas no pueden obtener el bloqueo, aunque está accediendo a un método diferente, no obtiene el bloqueo y no puede acceder a él.
clase pública twosyncmethod {public static void main (string [] args) {final twosyncmethod twosyncmethod = new twosyncMethod (); Thread t1 = new Thread (new runnable () {public void run () {twosyncmethod.syncmethod1 ();}}, "a"); t1.start (); Thread t2 = new Thread (new runnable () {public void run () {twosyncmethod.syncmethod2 ();}}, "b"); t2.start (); } public sincronizado void syncMethod1 () {for (int i = 0; i <5; i ++) {System.out.println (Thread.CurrentThread (). getName () + "en SyncMethod1 ():" + i); intente {thread.sleep (500); } capt (interruptedException IE) {}}} public sincronizado void syncmethod2 () {for (int i = 0; i <5; i ++) {system.out.println (thread.currentThread (). getName () + "at sincmethod2 ():" + i); intente {thread.sleep (500); } capt (interruptedException es decir) {}}}}Resultado de salida:
A AT SYNCMETHOD1 (): 0A AT SYNCMETHOD1 (): 1A AT SYNCMETHOD1 (): 2A AT SYNCMETHOD1 (): 3A AT SYNCMETHOD1 (): 4B AT SYNCMETHOD2 (): 0B AT SYNCMETHOD2 (): 1B AT SINCMETHOD2 (): 2B AT SYNCMETHOD2 (): 3B syncMethod2 (): 4