que - swingworker java example
El programa se bloquea si el subproceso se crea en un bloque de inicializador estático (4)
Esto es lo que creo que sucede:
- El hilo principal intenta inicializar
StaticInitializer
. Esto implica bloquear el objetoClass
correspondiente. - Mientras aún mantiene el bloqueo, el hilo principal genera otro hilo y espera a que termine .
- El método
run()
otro subproceso intenta acceder alstate
, lo que requiere queStaticInitializer
esté completamente inicializado; esto implica esperar en el mismo bloqueo que en el paso 1.
Resultado final: un punto muerto.
Consulte el JLS para obtener una descripción detallada del procedimiento de inicialización .
Si mueve t1.join()
en main()
, todo funciona.
Me he encontrado con una situación en la que mi programa se bloquea, parece un punto muerto. Pero intenté resolverlo con jconsole y visualvm, pero no detectaron ningún punto muerto. Código de muestra:
public class StaticInitializer {
private static int state = 10;
static {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
state = 11;
System.out.println("Exit Thread");
}
});
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("exiting static block");
}
public static void main(String...strings) {
System.out.println(state);
}
}
Cuando ejecuto esto en el modo de depuración, pude ver el control llegando a @Override public void run () {state = 11;
pero tan pronto como se ejecuta el estado = 11, simplemente se bloquea / interbloqueo. Busqué en diferentes publicaciones en stackoverflow y pensé que los inicializadores estáticos son seguros para subprocesos, pero en ese caso jconsole debería informar de esto. Acerca del hilo principal, jconsole dice que está en estado de espera, y eso está bien. Pero para el subproceso creado en el bloque de inicializador estático, jconsole dice que está en estado RUNNABLE y no está bloqueado. Estoy confundido y aquí falta algún concepto. Por favor, ayúdame.
No estás empezando otro hilo, te estás uniendo . Ese nuevo hilo debe esperar a que StaticInitializer
se inicialice completamente antes de que pueda continuar, porque está intentando establecer el campo de state
... y la inicialización ya está en curso, por lo que espera. Sin embargo, va a estar esperando para siempre, porque esa inicialización está esperando a que termine ese nuevo hilo. Punto muerto clásico.
Consulte la sección 12.4.2 de la Especificación del lenguaje Java para obtener detalles sobre lo que implica la inicialización de clases. Es importante destacar que el subproceso de inicialización "poseerá" el monitor para StaticInitializer.class
, pero el nuevo subproceso estará esperando para adquirir ese monitor.
En otras palabras, su código es un poco como este código no inicializador (manejo de excepciones elidido).
final Object foo = new Object();
synchronized (foo)
{
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (foo) {
System.out.println("In the new thread!");
}
});
t1.start();
t1.join();
});
Si puede comprender por qué ese código se bloquea, es básicamente el mismo para su código.
La moraleja es no hacer mucho trabajo en inicializadores estáticos.
Pude hacer que su programa se ejecutara comentando el state = 11;
de la línea state = 11;
No puede establecer el estado = 11 hasta que haya completado la inicialización. No puede completar la inicialización hasta que t1 termine de ejecutarse. T1 no puede terminar de ejecutarse hasta que establezca el estado = 11. Punto muerto.
la carga de clases es una especie de tiempo sensible en el jvm. cuando las clases se están inicializando, mantienen un bloqueo interno de jvm que pausará cualquier otro subproceso que intente trabajar con la misma clase. por lo tanto, lo más probable es que su subproceso generado esté esperando que la clase StaticInitializer se inicialice completamente antes de continuar. sin embargo, su clase StaticInitializer está esperando a que se complete el hilo antes de que se inicialice por completo. por lo tanto, punto muerto.
por supuesto, si realmente está tratando de hacer algo como esto, el hilo secundario es superfluo, ya que se está uniendo justo después de iniciarlo (por lo que también puede ejecutar ese código directamente).
ACTUALIZAR:
mi suposición de por qué no se detecta el interbloqueo es porque se está produciendo a un nivel mucho más bajo que el nivel en el que funciona el código de detección de interbloqueo estándar. ese código funciona con el bloqueo normal de objetos, mientras que esto es un asunto interno profundo de jvm.