studio - ejemplos de clases atributos y metodos en java
Inicialización de clase y método de clase sincronizada (4)
Mi comprensión del texto citado es que el proceso de inicialización de clase se completa ( se inicializará ) antes de invocar un método estático declarado por T.
se inicializará implica que el proceso de inicialización se ha iniciado y ha finalizado.
Por lo tanto, no debería ser posible (a mi entender) que, mientras se ejecuta el inicializador estático porque el hilo A llamó a la print
, otro hilo ya puede print
.
El Capítulo 12.4.2 del JLS describe el procedimiento de inicialización detallado, que se encarga de inicializar las clases en un entorno multiproceso.
En mi aplicación, hay una clase como la siguiente:
public class Client {
public synchronized static print() {
System.out.println("hello");
}
static {
doSomething(); // which will take some time to complete
}
}
Esta clase se usará en un entorno multi thread, muchos hilos pueden llamar al método Client.print () simultáneamente. Me pregunto si hay alguna posibilidad de que thread-1 active la inicialización de la clase, y antes de que se complete la inicialización de la clase, thread-2 ingrese al método de impresión e imprima la cadena "hola".
Veo este comportamiento en un sistema de producción (64 bit JVM + Windows 2008R2), sin embargo, no puedo reproducir este comportamiento con un programa simple en ningún entorno.
En la especificación de lenguaje Java, sección 12.4.1 (http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html), dice:
Una clase o interfaz de tipo T se inicializará inmediatamente antes de la primera aparición de cualquiera de los siguientes:
- T es una clase y se crea una instancia de T.
- T es una clase y se invoca un método estático declarado por T.
- Se asigna un campo estático declarado por T.
- Se utiliza un campo estático declarado por T y la referencia al campo no es una constante de tiempo de compilación (§15.28). Las referencias a las constantes de tiempo de compilación se deben resolver en tiempo de compilación a una copia del valor constante de tiempo de compilación, por lo que los usos de dicho campo nunca causan inicialización.
De acuerdo con este párrafo, la inicialización de la clase tendrá lugar antes de la invocación del método estático, sin embargo, no está claro si la inicialización de la clase debe completarse antes de la invocación del método estático. JVM debe ordenar que se complete la inicialización de clase antes de ingresar su método estático de acuerdo con mi intuición, y parte de mi experimento es compatible con mi suposición. Sin embargo, vi el comportamiento opuesto en otro entorno. ¿Alguien puede arrojar algo de luz sobre esto?
Cualquier ayuda es apreciada, gracias.
Si el código se está ejecutando en algunos contenedores , como Servlet, puede inicializarlo en el ciclo de vida del contenedor.
Si su "entorno de múltiples hilos" utiliza cargadores de múltiples clases para cargar su clase de Cliente, podría obtener varias instancias de Cliente, cada una de las cuales ejecutaría el inicializador estático antes de ejecutar cualquier llamada de Client.print (). Verías algo así como
doSomething
hello
doSomething
hello
hello
hello
Tengo un código de muestra que muestra esto, pero la versión actual es un poco difícil de ejecutar. Si quieres, puedo limpiarlo y publicarlo.
Ejecutar bloques estáticos que se consideran parte de la inicialización de clases:
La inicialización de una clase consiste en ejecutar sus inicializadores estáticos y los inicializadores para campos estáticos (variables de clase) declarados en la clase ...
Está garantizado por la especificación de JVM que eso se hará de manera segura. Para citar JLS sección 12.4.2 Procedimiento detallado de inicialización :
Debido a que el lenguaje de programación Java tiene múltiples subprocesos, la inicialización de una clase o interfaz requiere una sincronización cuidadosa, ya que algunos otros subprocesos pueden estar intentando inicializar la misma clase o interfaz al mismo tiempo. También existe la posibilidad de que la inicialización de una clase o interfaz se pueda solicitar recursivamente como parte de la inicialización de esa clase o interfaz; por ejemplo, un inicializador variable en la clase A podría invocar un método de una clase B no relacionada, que a su vez podría invocar un método de clase A. La implementación de la máquina virtual Java es responsable de cuidar la sincronización y la inicialización recursiva ...
En más detalle, se implementa adquiriendo el bloqueo en el objeto Class:
El procedimiento para inicializar una clase o interfaz es el siguiente:
- Sincronice (§14.19) en el objeto de clase que representa la clase o interfaz a ser inicializada
Su método está static synchronized
y también requiere bloqueo en el objeto Class. Como JVM adquiere el mismo bloqueo durante la inicialización de la clase, no es posible que un subproceso inicialice la clase y que otro ejecute static synchronized
método static synchronized
. Todas las citas están tomadas de JLS . Espero que sea útil. Por cierto, ¿cómo sabes que la impresión se produce antes de que finalice la inicialización de la clase?
EDITAR: En realidad estoy equivocado sobre la suposición de que solo static synchronized
no podría ejecutarse en paralelo con la inicialización de la clase. Cualquier método en la clase no podría ejecutarse hasta que finalice la inicialización de la clase.