Este artículo describe la diferencia entre sincronizado (bloqueo de objetos) y sincronizado estático (bloqueo de clase) en Java. Compártelo para su referencia, como sigue:
La diferencia entre sincronizado y sincronizado estático
Al analizar el análisis de estos dos usos, podemos entender el concepto de bloqueo en Java. Uno es un bloqueo de instancia (bloqueado en un objeto de instancia. Si la clase es un singleton, entonces el bloqueo también tiene el concepto de bloqueo global), y el otro es un bloqueo global (el bloqueo está dirigido a una clase. No importa cuántos objetos sea la instancia, los hilos comparten el bloqueo). El bloqueo de la instancia corresponde a la palabra clave sincronizada, mientras que el bloqueo de clase (bloqueo global) corresponde al sincronizado estático (o bloqueado en la clase o objeto de carga de clase de la clase).
El siguiente artículo ofrece un buen resumen:
1. La diferencia entre sincronizado y estático sincronizado
sincronizado bloquea la instancia actual (objeto actual) de la clase para evitar que otros hilos accedan a todos los bloques sincronizados de la instancia de la clase al mismo tiempo. Tenga en cuenta que esta es la "instancia actual de la clase". No existe tal restricción en dos casos diferentes de la clase.
Luego, el sincronizado estático controla el acceso concurrente de todas las instancias de la clase, y el sincronizado estático restringe todas las instancias de la clase en múltiples hilos para acceder al bloque de código correspondiente a la clase en JVM al mismo tiempo. De hecho, si hay sincronizado en un método o un bloque de código en una clase, después de generar una instancia de la clase, la instancia también tendrá un bloque de monitoreo para evitar que los hilos accedan simultáneamente al bloque de protección sincronizado de la instancia. Sincronizado estático es un bloque de monitoreo común a todas las instancias de la clase. Esta es la diferencia entre los dos. En otras palabras, sincronizado es equivalente a esto. Syncronized, mientras que el sincronizado estático es equivalente a algo. (Dirigido más tarde)
Un autor japonés, el "Patrón de diseño multithreadado de Java Múltiple" de Jie Chenghao tiene una columna como esta:
Clase pulbic algo () {public sincronizado Void issynca () {} sincronizado Void issyncb () {} public static sincronizado void csynca () {} public sincronizado sincronizado void csyncb () {}}Entonces, si hay dos instancias x e y de algo de clase, ¿cuál es el caso cuando el siguiente grupo de métodos se accede simultáneamente por múltiples hilos?
axissynca () y x.issyncb ()
bxissynca () y y.issynca ()
cxcsynca () y y.csyncb ()
dxissynca () y algo.csynca ()
Aquí, está claro que se puede juzgar:
A, todos son accesos de dominio sincronizados a la misma instancia (x) y, por lo tanto, no se pueden acceder simultáneamente. (No se puede acceder a diferentes dominios sincronizados a los que accede x en múltiples requisitos simultáneos)
Si se accede a X.issynca () en múltiples hilos, porque sigue siendo la misma instancia y bloqueada en el mismo método, no se puede acceder en múltiples hilos al mismo tiempo. (El mismo dominio sincronizado que accede a X en múltiples lecturas no se puede acceder al mismo tiempo)
B, es para diferentes instancias, por lo que se puede acceder al mismo tiempo (los bloqueos de objetos no tienen restricciones de bloqueo para diferentes instancias de objetos)
C, debido a que está sincronizado estático, las diferentes instancias aún estarán restringidas, lo cual es equivalente a algo.issynca () y algo.issyncb (), por lo que no se puede acceder al mismo tiempo.
Entonces, ¿qué pasa con D?, Se puede acceder a la respuesta en el libro simultáneamente. La razón de la respuesta es que Synchronzied es que el método de instancia y el método de clase sincronizado son diferentes del bloqueo.
El análisis personal significa que los sincronizados sincronizados y estáticos son equivalentes a dos pandillas, cada una de las cuales tiene su propio control, y no hay restricción entre sí y se puede acceder al mismo tiempo.
Por ejemplo:
clase pública testSynchronized {public sincronizado vacío test1 () {int i = 5; while (i--> 0) {System.out.println (Thread.CurrentThread (). getName () + ":" + i); intente {thread.sleep (500); } capt (interruptedException IE) {}}} public static sincronizado vacío test2 () {int i = 5; while (i--> 0) {System.out.println (Thread.CurrentThread (). getName () + ":" + i); intente {thread.sleep (500); } capt (interruptedException IE) {}}} public static void main (string [] args) {final testSynChronized myt2 = new testSynChronized (); Thread test1 = new Thread (new runnable () {public void run () {myt2.test1 ();}}, "test1"); Thread test2 = new Thread (new runnable () {public void run () {testSynchronized.test2 ();}}, "test2"); test1.start (); test2.start (); // testRunnable tr = new testRunnable (); // hilo test3 = nuevo hilo (tr); // test3.start (); }}test1: 4 test2: 4 test1: 3 test2: 3 test2: 2 test1: 2 test2: 1 test1: 1 test1: 0 test2: 0
El código anterior sincronizado modifica el método estático y el método de instancia al mismo tiempo, pero los resultados en ejecución se realizan alternativamente, lo que demuestra que los bloqueos de clase y los bloqueos de objetos son dos cerraduras diferentes, que controlan diferentes regiones, y no interfieren entre sí. Del mismo modo, mientras que los hilos obtienen bloqueos de objetos, también pueden obtener este tipo de bloqueo, es decir, obtienen dos cerraduras al mismo tiempo, lo que está permitido.
en conclusión:
R: La estática sincronizada es el alcance de una determinada clase. Csync static {} sincronizado evita que múltiples instancias en múltiples hilos accedan al método estático sincronizado en esta clase al mismo tiempo. Funciona en todas las instancias de objetos de una clase.
B: Sincronizado es el alcance de una instancia. Sincronizado isSync () {} evita que esta instancia acceda al método sincronizado de esta clase al mismo tiempo.
De hecho, es muy simple de resumir.
2. La diferencia entre el método sincronizado y el código sincronizado rápido
No hay diferencia entre los métodos sincronizados () {} y sincronizado (this) {}, pero los métodos sincronizados () {} son convenientes para la comprensión de lectura, mientras que sincronizado (esto) {} puede controlar con mayor precisión las áreas de acceso de conflicto y, a veces, y a veces funciona de manera más eficiente.
Comparación de la eficiencia entre dos métodos:
1. Sincronice el bloque, el código es el siguiente:
import java.util.concurrent.countdownLatch; import java.util.concurrent.executorservice; import java.util.concurrent.executors; clase pública testSynchronized { / ** * @param args * / public static void main (string [] args) {ExecutorService Service = Ejecutors.newCachedThreadPool (); Final CountDownLatch CDORDER = new CountdownLatch (1); Final CountdownLatch CDANSWER = new CountdownLatch (3); SynchonizedClass final SC = new SynchonizedClass (); for (int i = 0; i <3; i ++) {runnable runnable = new runnable () {public void run () {try {cdorder.await (); sc.Start (); CDANSWER.COUNTDOWN (); } catch (Exception e) {E.PrintStackTrace (); }}}; servicio.Execute (runnable); } try {thread.sleep ((long) (math.random ()*10000)); System.out.println ("Thread" + Thread.CurrentThread (). GetName () + "Publicar comando de ejecución"); CDORDER.COUNTDOWN (); largo BegiNtime = System.CurrentTimemillis (); System.out.println ("Thread" + Thread.CurrentThread (). GetName () + "El comando se ha enviado, esperando el resultado"); CDANSWER.AWAIT (); System.out.println ("Thread" + Thread.CurrentThread (). GetName ()) + "Todos los resultados de respuesta se han recibido, el tiempo tomado es:" + (System.CurrentTimemillis ()-BegIntime)); } catch (Exception e) {E.PrintStackTrace (); } servicio.shutdown (); }} class SynchonizedClass {public void start () lanza interruptedException {Thread.sleep (100); // Ejecutar otra lógica para consumir tiempo sincronizado (this) {System.out.println ("lo ejecuté con 10 ms"); }}} Los resultados de la operación son los siguientes:
PRINCIÓN PRINCIPAL DEL SUMPRESO El comando de ejecución, el subproceso principal ha enviado el comando, esperando el resultado que ejecuté y usé 10 ms
He corrido usando 10 ms
He corrido usando 10 ms
El hilo principal ha recibido todos los resultados de respuesta, y el tiempo tomado es: 110
El método de sincronización, el código es el siguiente:
import java.util.concurrent.countdownLatch; import java.util.concurrent.executorservice; import java.util.concurrent.executors; clase pública testSynchronized { / ** * @param args * / public static void main (string [] args) {ExecutorService Service = Ejecutors.newCachedThreadPool (); Final CountDownLatch CDORDER = new CountdownLatch (1); Final CountdownLatch CDANSWER = new CountdownLatch (3); SynchonizedClass final SC = new SynchonizedClass (); for (int i = 0; i <3; i ++) {runnable runnable = new runnable () {public void run () {try {cdorder.await (); sc.Start (); CDANSWER.COUNTDOWN (); } catch (Exception e) {E.PrintStackTrace (); }}}; servicio.Execute (runnable); } try {thread.sleep ((long) (math.random ()*10000)); System.out.println ("Thread" + Thread.CurrentThread (). GetName () + "Publicar comando de ejecución"); CDORDER.COUNTDOWN (); largo BegiNtime = System.CurrentTimemillis (); System.out.println ("Thread" + Thread.CurrentThread (). GetName () + "El comando se ha enviado, esperando el resultado"); CDANSWER.AWAIT (); System.out.println ("Thread" + Thread.CurrentThread (). GetName ()) + "Todos los resultados de respuesta se han recibido, el tiempo tomado es:" + (System.CurrentTimemillis ()-BegIntime)); } catch (Exception e) {E.PrintStackTrace (); } servicio.shutdown (); }} clase SynchonizedClass {public sincronizado void start () lanza interruptedException {Thread.sleep (100); // Ejecutar otro tiempo lógico // sincronizado (this) {System.Println ("usé 10 ms"); //}}}Los resultados de la operación son los siguientes:
PRINCIÓN PRINCIPAL DEL SUMPRESO El comando de ejecución, el subproceso principal ha enviado el comando, esperando el resultado que ejecuté y usé 10 ms
He corrido usando 10 ms
He corrido usando 10 ms
El hilo principal ha recibido todos los resultados de respuesta, y el tiempo tomado es: 332
La diferencia entre los dos es: 222 ms.
La comparación muestra que los bloques de código sincrónicos son más eficientes que los métodos de sincronización.
Memoria complementaria:
1. Hay dos ámbitos de palabras clave sincronizadas:
1) Está dentro de una instancia de objeto. Amethod () {} sincronizado puede evitar que múltiples hilos accedan al método sincronizado de este objeto al mismo tiempo (si un objeto tiene múltiples métodos sincronizados, siempre que un hilo acceda a uno de los métodos sincronizados, otros hilos no pueden acceder a ningún método sincronizado en el objeto al mismo tiempo). En este momento, el método sincronizado de diferentes instancias de objetos es ininterrumpido. Es decir, otros hilos aún pueden acceder al método sincronizado en otra instancia de objeto de la misma clase al mismo tiempo;
2) Es el alcance de una determinada clase. AstaticMethod static ssatic {} sincronizado evita que diferentes objetos de instancia (o el mismo objeto de instancia) en múltiples subprocesos accedan al método estático sincronizado en esta clase al mismo tiempo. Funciona en todas las instancias de objetos de una clase.
2. Además de usar la palabra clave sincronizada antes del método, la palabra clave sincronizada también se puede usar en un bloque en el método, lo que indica que solo se realiza un acceso mutuamente excluyente en los recursos de este bloque. El uso es: sincronizado (this) {/*block*/} (o sincronizado (obj) {/*block*/}), y su alcance es el objeto actual;
3. La palabra clave sincronizada no se puede heredar. Es decir, el método de la clase base sincronizada f () {} no se sincroniza automáticamente f () {} en la clase heredada, sino que se convierte en f () {}. La clase de herencia requiere que especifique explícitamente que uno de sus métodos está sincronizado;
Alguna comprensión de sincronizado (esto) (explique bien el bloqueo del objeto, preste atención a esta palabra clave en él)
1. Cuando dos hilos concurrentes acceden a este bloque de código sincronizado (este) sincronizado en el mismo objeto de objeto, solo se puede ejecutar un hilo dentro de una vez. Otro hilo debe esperar a que el hilo actual ejecute este bloque de código antes de que pueda ejecutar el bloque de código.
2. Sin embargo, cuando un hilo accede a un bloque de código de sincronización sincronizado (este) de un objeto, otro hilo aún puede acceder al bloque de código de sincronización no sincronizado (esto) en ese objeto.
3. Es particularmente crítico que cuando un hilo accede a un bloque de código de sincronización sincronizado (este) de un objeto, otros subprocesos bloquearán el acceso a todos los otros bloques de código de sincronización sincronizados (esto) en el objeto.
4. El tercer ejemplo también se aplica a otros bloques de código sincrónicos. Es decir, cuando un hilo accede a un bloque de código de sincronización sincronizado (este) de un objeto, obtiene el bloqueo del objeto de este objeto. Como resultado, otros subprocesos acceden a todas las partes de código sincrónico del objeto del objeto se bloquea temporalmente.
5. Las reglas anteriores también se aplican a otros bloqueos de objetos.
Agregue un código para facilitar las pruebas de palabras clave sincronizadas (modificación simple)
public class testSynCronized {public void test1 () {sincronizado (this) {int i = 5; while (i--> 0) {System.out.println (Thread.CurrentThread (). getName () + ":" + i); intente {thread.sleep (500); } capt (interruptedException IE) {}}}} public sincronizado void test2 () {int i = 5; while (i--> 0) {System.out.println (Thread.CurrentThread (). getName () + ":" + i); intente {thread.sleep (500); } capt (interruptedException IE) {}}} public sincronizado void test3 () {int i = 5; while (i--> 0) {System.out.println (Thread.CurrentThread (). getName () + ":" + i); intente {thread.sleep (500); } capt (interruptedException IE) {}}} public static void main (string [] args) {final testSynChronized myt2 = new testSynChronized (); final testSyncronized myt3 = new testSynChronized (); Thread test1 = new Thread (new runnable () {public void run () {myt2.test2 ();}}, "test1"); Thread test2 = new Thread (new runnable () {public void run () {myt2.test3 ();}}, "test3"); test1.start () ;; test2.start (); }} Resultados de ejecución:
test1: 4test1: 3test1: 2test1: 1test1: 0test3: 4test3: 3test3: 2test3: 1Test3: 0
A continuación nos centramos en el uso de SyCronized en Java, que es específicamente: el método de sincronización y la palabra clave sincronizada del bloque sincronizado, que incluye dos usos: el método sincronizado y el bloque sincronizado.
1. Método sincronizado: declare el método sincronizado agregando la palabra clave sincronizada a la declaración del método. como:
Public sincronizado accessval (int newval);
El método sincronizado controla el acceso a las variables de miembros de la clase: cada instancia de clase corresponde a un bloqueo, y cada método sincronizado debe obtener el bloqueo de la instancia de clase que llama al método antes de que pueda ejecutarse. De lo contrario, el hilo al que pertenece está bloqueado. Una vez que se ejecuta el método, ocupará exclusivamente el bloqueo. El bloqueo no se lanzará hasta que regrese del método. El hilo bloqueado puede obtener el bloqueo y volver a ingresar el estado ejecutable. Este mecanismo asegura que al mismo tiempo, para cada instancia de clase, como máximo una de las funciones de los miembros declaradas sincronizadas, se encuentre en un estado ejecutable (porque a lo sumo uno puede obtener el bloqueo correspondiente a la instancia de clase), evitando así efectivamente los conflictos de acceso de las variables de los miembros de la clase (siempre que todos los métodos posibles para acceder a las variables de los miembros de la clase se declaren sincronizados).
En Java, no solo las instancias de clase, cada clase también corresponde a un bloqueo, por lo que podemos declarar que la función de miembro estático de la clase como estática sincronizada para controlar su acceso a las variables de miembros estáticos de la clase.
La desventaja del método sincronizado: declarar un método grande como sincronizado afectará en gran medida la eficiencia. Por lo general, si el método de la clase de hilo () se declara como sincronizado, ya que se ha ejecutado a lo largo de la vida del hilo, hará que nunca tenga éxito en ningún método sincronizado de esta clase. Por supuesto, podemos resolver este problema colocando el código que accede a las variables de los miembros de la clase en un método especial, declarándolo como sincronizado y llamándolo en el método principal, pero Java nos proporciona una mejor solución, es decir, el bloque sincronizado.
2. Bloque sincronizado: declare el bloque sincronizado a través de la palabra clave sincronizada. La sintaxis es la siguiente:
sincronizado (syncObject) {// código que permite el control de acceso} El bloque sincronizado es un bloque de código en el que el código debe obtener un bloqueo del syncObject de objeto (como se mencionó anteriormente, puede ser una instancia o clase de clase) antes de que pueda ejecutarse. El mecanismo específico es el mismo que el descrito anteriormente. Dado que se puede dirigir en cualquier bloque de código y los objetos bloqueados se pueden especificar en cualquier momento, es más flexible.
Aviso:
Al usar palabras clave sincronizadas, debe evitar usar métodos de sueño o rendimiento en métodos sincronizados o bloques sincronizados tanto como sea posible, porque los bloqueos de programa sincronizados ocupan las bloqueos de objetos, por lo que si descansa, otros hilos solo se pueden ejecutar mientras se espera que se despierte y termine de ejecutar. No solo afecta seriamente la eficiencia, sino que tampoco es lógico.
Del mismo modo, no tiene sentido llamar al método Yeild en el bloque del programa sincrónico para renunciar al recurso de la CPU, porque usted ocupa el bloqueo y otros hilos mutex aún no pueden acceder al bloque de programa sincrónico. Por supuesto, los hilos que no están relacionados con bloques de programas sincrónicos pueden obtener más tiempo de ejecución.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.