Java 101 de este mes concluye la serie de subprocesos centrándose en los grupos de subprocesos, la volatilidad, las variables locales de subprocesos, los temporizadores y la ThreadDeath
clase.
Comprensión de los hilos de Java: lea la serie completa
- Parte 1: Introducción a subprocesos y ejecutables
- Parte 2: sincronización de subprocesos
- Parte 3: programación de subprocesos, espera / notificación e interrupción de subprocesos
- Parte 4: grupos de subprocesos, volatilidad, variables locales de subprocesos, temporizadores y muerte de subprocesos
Grupos de hilos
En un programa de servidor de red, un subproceso espera y acepta solicitudes de programas cliente para ejecutar, por ejemplo, transacciones de base de datos o cálculos complejos. El hilo normalmente crea un hilo nuevo para manejar la solicitud. Dependiendo del volumen de solicitudes, pueden estar presentes simultáneamente muchos subprocesos diferentes, lo que complica la administración de subprocesos. Para simplificar la gestión de subprocesos, los programas organizan sus subprocesos con grupos de subprocesos : java.lang.ThreadGroup
objetos que agrupan los objetos Thread
(y Thread
subclase) de subprocesos relacionados . Por ejemplo, su programa puede usar ThreadGroup
para agrupar todos los hilos de impresión en un grupo.
Nota: Para simplificar la discusión, me refiero a los grupos de hilos como si organizaran hilos. En realidad, los grupos de subprocesos organizan Thread
(y Thread
subclasifican) objetos asociados con subprocesos.
Java requiere que todos los subprocesos y todos los grupos de subprocesos, salvo el grupo de subprocesos raíz, se system
unan a otro grupo de subprocesos. Esa disposición conduce a una estructura jerárquica de grupos de subprocesos, que la figura siguiente ilustra en un contexto de aplicación.

En la parte superior de la estructura de la figura está el system
grupo de hilos. El system
grupo creado por JVM organiza los subprocesos de JVM que se ocupan de la finalización de objetos y otras tareas del sistema, y sirve como grupo de subprocesos raíz de la estructura jerárquica del grupo de subprocesos de una aplicación. Justo debajo system
está el main
grupo de subprocesos creado por JVM , que es system
el grupo de subprocesos (subgrupo, para abreviar). main
contiene al menos un subproceso: el subproceso principal creado por JVM que ejecuta instrucciones de código de bytes en el main()
método.
Debajo del main
grupo se encuentran los subgrupos subgroup 1
y subgroup 2
, subgrupos creados por la aplicación (que crea la aplicación de la figura). Además, subgroup 1
grupos de tres hilos de aplicación creados: thread 1
, thread 2
, y thread 3
. En contraste, subgroup 2
los grupos de un hilo de aplicación creado: my thread
.
Ahora que conoce los conceptos básicos, comencemos a crear grupos de hilos.
Cree grupos de hilos y asocie hilos con esos grupos
La ThreadGroup
documentación del SDK de la clase revela dos constructores: ThreadGroup(String name)
y ThreadGroup(ThreadGroup parent, String name)
. Ambos constructores crean un grupo de hilos y le dan un nombre, como name
especifica el parámetro. Los constructores difieren en su elección de qué grupo de hilos sirve como padre del grupo de hilos recién creado. Cada grupo de subprocesos, excepto system
, debe tener un grupo de subprocesos principal. Porque ThreadGroup(String name)
, el padre es el grupo de subprocesos del subproceso que llama ThreadGroup(String name)
. Por ejemplo, si el hilo principal llama ThreadGroup(String name)
, el grupo de hilos recién creado tiene el grupo del hilo principal como padre— main
. Porque ThreadGroup(ThreadGroup parent, String name)
, el padre es el grupo al que hace parent
referencia. El siguiente código muestra cómo usar estos constructores para crear un par de grupos de hilos:
public static void main (String [] args) { ThreadGroup tg1 = new ThreadGroup ("A"); ThreadGroup tg2 = new ThreadGroup (tg1, "B"); }
En el código anterior, el hilo principal crea dos grupos de hilos: A
y B
. Primero, el hilo principal se crea A
llamando ThreadGroup(String name)
. El tg1
padre del grupo de hilos al que se hace referencia es main
porque main
es el grupo de hilos del hilo principal. En segundo lugar, el hilo principal crea B
llamando ThreadGroup(ThreadGroup parent, String name)
. La tg2
matriz de grupo de hilos -referenced es A
debido tg1
referencia 's pasa como argumento a ThreadGroup (tg1, "B")
y A
asociados con tg1
.
Sugerencia: una vez que ya no necesite una jerarquía de ThreadGroup
objetos, llame ThreadGroup
al void destroy()
método mediante una referencia al ThreadGroup
objeto en la parte superior de esa jerarquía. Si el ThreadGroup
objeto superior y todos los objetos del subgrupo carecen de objetos de hilo, destroy()
prepara esos objetos de grupo de hilo para la recolección de basura. De lo contrario, destroy()
lanza un IllegalThreadStateException
objeto. Sin embargo, hasta que anule la referencia al ThreadGroup
objeto superior (asumiendo que una variable de campo contiene esa referencia), el recolector de basura no puede recolectar ese objeto. Haciendo referencia al objeto superior, puede determinar si se realizó una llamada anterior al destroy()
método llamando ThreadGroup
al boolean isDestroyed()
método de. Ese método devuelve verdadero si se destruyó la jerarquía del grupo de subprocesos.
Por sí mismos, los grupos de hilos son inútiles. Para ser de alguna utilidad, deben agrupar subprocesos. Puede agrupar subprocesos en grupos de subprocesos pasando ThreadGroup
referencias a los Thread
constructores apropiados :
ThreadGroup tg = new ThreadGroup ("subgroup 2"); Thread t = new Thread (tg, "my thread");
El código anterior primero crea un subgroup 2
grupo con main
el grupo principal. (Supongo que el hilo principal ejecuta el código). El siguiente código crea un my thread
Thread
objeto en el subgroup 2
grupo.
Ahora, creemos una aplicación que produzca la estructura jerárquica de grupos de hilos de nuestra figura:
Listado 1. ThreadGroupDemo.java
// ThreadGroupDemo.java class ThreadGroupDemo { public static void main (String [] args) { ThreadGroup tg = new ThreadGroup ("subgroup 1"); Thread t1 = new Thread (tg, "thread 1"); Thread t2 = new Thread (tg, "thread 2"); Thread t3 = new Thread (tg, "thread 3"); tg = new ThreadGroup ("subgroup 2"); Thread t4 = new Thread (tg, "my thread"); tg = Thread.currentThread ().getThreadGroup (); int agc = tg.activeGroupCount (); System.out.println ("Active thread groups in " + tg.getName () + " thread group: " + agc); tg.list (); } }
ThreadGroupDemo
crea el grupo de hilos apropiado y los objetos de hilo para reflejar lo que ves en la figura anterior. Para probar que los grupos subgroup 1
y subgroup 2
son main
los únicos subgrupos, ThreadGroupDemo
haga lo siguiente:
- Recupera una referencia a del hilo principal
ThreadGroup
objeto llamandoThread
'estática scurrentThread()
método (que devuelve una referencia a del hilo principalThread
objeto) seguidos porThread
' sThreadGroup getThreadGroup()
método. - Llama
ThreadGroup
alint activeGroupCount()
método de laThreadGroup
referencia recién devuelta para devolver una estimación de los grupos activos dentro del grupo de subprocesos del hilo principal. - Llama
ThreadGroup
alString getName ()
método para devolver el nombre del grupo de hilos del hilo principal. ThreadGroup
Elvoid list ()
método de las llamadas para imprimir en los detalles del dispositivo de salida estándar en el grupo de subprocesos del hilo principal y todos los subgrupos.
Cuando se ejecuta, ThreadGroupDemo
muestra la siguiente salida:
Active thread groups in main thread group: 2 java.lang.ThreadGroup[name=main,maxpri=10] Thread[main,5,main] Thread[Thread-0,5,main] java.lang.ThreadGroup[name=subgroup 1,maxpri=10] Thread[thread 1,5,subgroup 1] Thread[thread 2,5,subgroup 1] Thread[thread 3,5,subgroup 1] java.lang.ThreadGroup[name=subgroup 2,maxpri=10] Thread[my thread,5,subgroup 2]
Salida que comienza con los Thread
resultados de list()
las llamadas internas de Thread
'al toString()
método de', un formato de salida que describí en la Parte 1. Junto con esa salida, verá la salida que comienza con java.lang.ThreadGroup
. Esa salida identifica el nombre del grupo de subprocesos seguido de su máxima prioridad.
Grupos de prioridad y subprocesos
La máxima prioridad de un grupo de subprocesos es la prioridad más alta que cualquiera de sus subprocesos puede alcanzar. Considere el programa de servidor de red mencionado anteriormente. Dentro de ese programa, un hilo espera y acepta solicitudes de programas cliente. Antes de hacer eso, el hilo de espera / aceptación-solicitud puede crear primero un grupo de hilos con una prioridad máxima justo debajo de la prioridad de ese hilo. Más tarde, cuando llega una solicitud, el subproceso de espera / aceptación de solicitud crea un nuevo subproceso para responder a la solicitud del cliente y agrega el nuevo subproceso al grupo de subprocesos creado anteriormente. La prioridad del nuevo hilo se reduce automáticamente al máximo del grupo de hilos. De esa manera, el subproceso de espera / aceptación de solicitud responde con más frecuencia a las solicitudes porque se ejecuta con más frecuencia.
Java assigns a maximum priority to each thread group. When you create a group, Java obtains that priority from its parent group. Use ThreadGroup
's void setMaxPriority(int priority)
method to subsequently set the maximum priority. Any threads that you add to the group after setting its maximum priority cannot have a priority that exceeds the maximum. Any thread with a higher priority automatically lowers when it joins the thread group. However, if you use setMaxPriority(int priority)
to lower a group's maximum priority, all threads added to the group prior to that method call keep their original priorities. For example, if you add a priority 8 thread to a maximum priority 9 group, and then lower that group's maximum priority to 7, the priority 8 thread remains at priority 8. At any time, you can determine a thread group's maximum priority by calling ThreadGroup
's int getMaxPriority()
method. To demonstrate priority and thread groups, I wrote MaxPriorityDemo
:
Listing 2. MaxPriorityDemo.java
// MaxPriorityDemo.java class MaxPriorityDemo { public static void main (String [] args) { ThreadGroup tg = new ThreadGroup ("A"); System.out.println ("tg maximum priority = " + tg.getMaxPriority ()); Thread t1 = new Thread (tg, "X"); System.out.println ("t1 priority = " + t1.getPriority ()); t1.setPriority (Thread.NORM_PRIORITY + 1); System.out.println ("t1 priority after setPriority() = " + t1.getPriority ()); tg.setMaxPriority (Thread.NORM_PRIORITY - 1); System.out.println ("tg maximum priority after setMaxPriority() = " + tg.getMaxPriority ()); System.out.println ("t1 priority after setMaxPriority() = " + t1.getPriority ()); Thread t2 = new Thread (tg, "Y"); System.out.println ("t2 priority = " + t2.getPriority ()); t2.setPriority (Thread.NORM_PRIORITY); System.out.println ("t2 priority after setPriority() = " + t2.getPriority ()); } }
When run, MaxPriorityDemo
produces the following output:
tg maximum priority = 10 t1 priority = 5 t1 priority after setPriority() = 6 tg maximum priority after setMaxPriority() = 4 t1 priority after setMaxPriority() = 6 t2 priority = 4 t2 priority after setPriority() = 4
Thread group A
(which tg
references) starts with the highest priority (10) as its maximum. Thread X
, whose Thread
object t1
references, joins the group and receives 5 as its priority. We change that thread's priority to 6, which succeeds because 6 is less than 10. Subsequently, we call setMaxPriority(int priority)
to reduce the group's maximum priority to 4. Although thread X
remains at priority 6, a newly-added Y
thread receives 4 as its priority. Finally, an attempt to increase thread Y
's priority to 5 fails, because 5 is greater than 4.
Note:setMaxPriority(int priority)
automatically adjusts the maximum priority of a thread group's subgroups.
In addition to using thread groups to limit thread priority, you can accomplish other tasks by calling various ThreadGroup
methods that apply to each group's thread. Methods include void suspend()
, void resume()
, void stop()
, and void interrupt()
. Because Sun Microsystems has deprecated the first three methods (they are unsafe), we examine only interrupt()
.
Interrupt a thread group
ThreadGroup
El interrupt()
método de 'permite que un hilo interrumpa los hilos y subgrupos de un grupo de hilos específico. Esta técnica resultaría apropiada en el siguiente escenario: El hilo principal de su aplicación crea varios hilos y cada uno realiza una unidad de trabajo. Debido a que todos los subprocesos deben completar sus respectivas unidades de trabajo antes de que cualquier subproceso pueda examinar los resultados, cada subproceso espera después de completar su unidad de trabajo. El hilo principal monitorea el estado de trabajo. Una vez que todos los demás hilos están esperando, el hilo principal llama interrupt()
para interrumpir las esperas de los demás hilos. Entonces esos hilos pueden examinar y procesar los resultados. El Listado 3 demuestra la interrupción del grupo de subprocesos:
Listado 3. InterruptThreadGroup.java
// InterruptThreadGroup.java class InterruptThreadGroup { public static void main (String [] args) { MyThread mt = new MyThread (); mt.setName ("A"); mt.start (); mt = new MyThread (); mt.setName ("B"); mt.start (); try { Thread.sleep (2000); // Wait 2 seconds } catch (InterruptedException e) { } // Interrupt all methods in the same thread group as the main // thread Thread.currentThread ().getThreadGroup ().interrupt (); } } class MyThread extends Thread { public void run () { synchronized ("A") { System.out.println (getName () + " about to wait."); try { "A".wait (); } catch (InterruptedException e) { System.out.println (getName () + " interrupted."); } System.out.println (getName () + " terminating."); } } }