¡Acostúmbrate a escribir juntos! Este es el día 11 de mi participación en el "Desafío de actualización de abril del nuevo plan diario de Nuggets", haga clic para ver los detalles del evento
Cómo usar sincronizado
Cada objeto en Java puede actuar como un candado, que se puede expresar de las siguientes tres formas:
- Modifica los métodos ordinarios, el bloqueo es el objeto de instancia actual;
- Decora el método de sincronización estática, el candado es el objeto Class de la clase actual
- Modificar el bloque de código, el candado es el objeto configurado en los paréntesis sincronizados;
Echemos un vistazo a estos métodos de bloqueo por ejemplo.
método sincronizado
public synchronized void addI
El método de sincronización está bloqueado. Después de usar el comando para convertir el archivo javap -c -v FileName.class en instrucciones de bytecode,
Los resultados principales son los siguientes:
public void addII(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=3, locals=3, args_size=2
.... 省略
public synchronized void addI(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC, java
Code:
stack=3, locals=3, args_size=2
复制代码
Puede ver que hay un indicador ACC_SYNCHRONIZED en el bloque del método de sincronización, lo que indica que este método está sincronizado. Los indicadores de métodos asincrónicos no tienen el indicador ACC_SYNCHRONIZED.
sincronización de métodos estáticos
public class InternalVariable {
public static void addIII(String username){
// ... 代码省略
}
}
复制代码
Descompilar para ver los resultados principales de la compilación:
public static synchronized void addIII(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=3, locals=3, args_size=1
复制代码
Comparado con el método ordinario, el método estático tiene un ACC_STATIC más en la bandera de banderas.
Bloque de código sincronizado
public class InternalVariable {
public void addIIII(String username) {
synchronized (this) {
// ... 代码
}
}
}
复制代码
Los resultados de la descompilación son los siguientes:
public void addIIII(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=3, locals=6, args_size=2
0: aload_0
1: dup
2: astore_2
3: monitorenter
// ... 省略
135: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
138: aload_2
139: monitorexit
140: goto 150
143: astore 5
145: aload_2
146: monitorexit
147: aload 5
149: athrow
150: return
复制代码
El bloque de código de sincronización tiene un monitorenter, pero dos monitorexit. Esto se debe a que la JVM generará automáticamente un controlador de excepciones para garantizar que el método pueda liberar el bloqueo normalmente cuando se produzca una excepción. El propósito es ejecutar la instrucción monitorexit.
Implementación subyacente sincronizada
La implementación subyacente de sincronizado depende de la JVM.La implementación de la sincronización en la JVM se implementa a través de las instrucciones monitor de entrada y salida del monitor de bloqueo del monitor, o implícitamente a través de la llamada al método (detección del indicador de sincronización) y la instrucción de retorno. Estos dos, el primero corresponde al bloque de código de sincronización, el último corresponde al método de sincronización, el método de sincronización estática.
Por lo tanto, el método de sincronización finalmente completa la sincronización del subproceso a través del bloqueo del monitor, lo que no viola la sincronización en la JVM a través de la entrada y salida del monitor.