¿El valor prio de volcado de subprocesos de Java no se corresponde con la prioridad de subprocesos reales en Linux?
Frecuentes
Visto 1,312 veces
8
Tengo la intención de usar prioridades de subprocesos dentro de mi código Java. La aplicación se ejecutará en mi sistema Linux:
>uname -a
Linux <host> 3.0.0-15-generic #26-Ubuntu SMP <date> x86_64 x86_64 x86_64 GNU/Linux
>java -version
java version "1.6.0_23"
OpenJDK Runtime Environment (IcedTea6 1.11pre) (6b23~pre11-0ubuntu1.11.10.1)
OpenJDK 64-Bit Server VM (build 20.0-b11, mixed mode)
Después de leer un poco en la Web, ahora comienzo mi aplicación de prueba con el siguiente comando:
sudo java -XX:+UseThreadPriorities -XX:ThreadPriorityPolicy=1 -jar ThreadPriorityTest.jar
La aplicación de prueba consta de las siguientes dos clases:
package ch.mypackage;
public class CountingRunnable implements Runnable {
private long count = 0;
private boolean goOn = true;
public long getCount() {
return count;
}
public void stop() {
goOn=false;
}
public void run() {
for(long iteration=0;goOn&&iteration<Long.MAX_VALUE;++iteration) {
++count;
}
}
}
package ch.mypackage;
public class PriorizedCountingThreads {
private static final int NUM_MILLIS_TO_COUNT_FOR = 1*60*1000;
private static CountingRunnable[] runnables;
private static Thread[] threads;
public static void main(String[] args) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
System.out.println("MIN_PRIORITY: "+Thread.MIN_PRIORITY);
System.out.println("MAX_PRIORITY: "+Thread.MAX_PRIORITY);
int numPriorityLevels = (Thread.MAX_PRIORITY-Thread.MIN_PRIORITY) + 1;
init(numPriorityLevels);
startThreads();
try {
Thread.sleep(NUM_MILLIS_TO_COUNT_FOR);
} catch (InterruptedException e) {
e.printStackTrace();
}
stopRunnables();
printCounts();
}
private static void printCounts() {
for (int i = 0; i < runnables.length; ++i) {
System.out.println(threads[i].getName() + " has priority: " + threads[i].getPriority() + " and count:" + runnables[i].getCount());
}
}
private static void stopRunnables() {
for (int i = 0; i < runnables.length; ++i) {
runnables[i].stop();
}
}
private static void startThreads() {
for (int i = 0; i < threads.length; ++i) {
threads[i].start();
}
}
private static void init(int numPriorityLevels) {
runnables = new CountingRunnable[numPriorityLevels];
threads = new Thread[runnables.length];
for (int i = 0; i < runnables.length; ++i) {
int priority = i + 1;
runnables[i] = new CountingRunnable();
threads[i] = new Thread(runnables[i]);
threads[i].setPriority(priority);
threads[i].setName("PriorityThread_" + priority);
}
}
}
Si dejo que el programa cuente durante un minuto (NUM_MILLIS_TO_COUNT_FOR=1601000), obtengo el siguiente resultado:
MIN_PRIORITY: 1
MAX_PRIORITY: 10
PriorityThread_1 has priority: 1 and count:12658044343
PriorityThread_2 has priority: 2 and count:19008431582
PriorityThread_3 has priority: 3 and count:30618946099
PriorityThread_4 has priority: 4 and count:34408365142
PriorityThread_5 has priority: 5 and count:36694025023
PriorityThread_6 has priority: 6 and count:40493710165
PriorityThread_7 has priority: 7 and count:42826305342
PriorityThread_8 has priority: 8 and count:42203891414
PriorityThread_9 has priority: 9 and count:43128747383
PriorityThread_10 has priority: 10 and count:43416371500
¡Según este resultado, las prioridades parecen tener el impacto esperado! Pero si genero un volcado de hilo con "jstack" o "kill -s QUIT", obtengo el siguiente resultado, lo que implica que CADA HILO TIENE LA MISMA PRIORIDAD (prio=10):
"PriorityThread_10" prio=10 tid=0x00007ff7e406f800 nid=0x12e6 runnable [0x00007ff7e2562000]
java.lang.Thread.State: RUNNABLE
at ch.mypackage.CountingRunnable.run(CountingRunnable.java:17)
at java.lang.Thread.run(Thread.java:679)
"PriorityThread_9" prio=10 tid=0x00007ff7e406d800 nid=0x12e5 runnable [0x00007ff7e2663000]
java.lang.Thread.State: RUNNABLE
at ch.mypackage.CountingRunnable.run(CountingRunnable.java:17)
at java.lang.Thread.run(Thread.java:679)
"PriorityThread_8" prio=10 tid=0x00007ff7e406b000 nid=0x12e4 runnable [0x00007ff7e2764000]
java.lang.Thread.State: RUNNABLE
at ch.mypackage.CountingRunnable.run(CountingRunnable.java:17)
at java.lang.Thread.run(Thread.java:679)
"PriorityThread_7" prio=10 tid=0x00007ff7e4069000 nid=0x12e3 runnable [0x00007ff7e2865000]
java.lang.Thread.State: RUNNABLE
at ch.mypackage.CountingRunnable.run(CountingRunnable.java:17)
at java.lang.Thread.run(Thread.java:679)
"PriorityThread_6" prio=10 tid=0x00007ff7e4067000 nid=0x12e2 runnable [0x00007ff7e2966000]
java.lang.Thread.State: RUNNABLE
at ch.mypackage.CountingRunnable.run(CountingRunnable.java:17)
at java.lang.Thread.run(Thread.java:679)
"PriorityThread_5" prio=10 tid=0x00007ff7e4065000 nid=0x12e1 runnable [0x00007ff7e2a67000]
java.lang.Thread.State: RUNNABLE
at ch.mypackage.CountingRunnable.run(CountingRunnable.java:17)
at java.lang.Thread.run(Thread.java:679)
"PriorityThread_4" prio=10 tid=0x00007ff7e4063000 nid=0x12e0 runnable [0x00007ff7e2b68000]
java.lang.Thread.State: RUNNABLE
at ch.mypackage.CountingRunnable.run(CountingRunnable.java:17)
at java.lang.Thread.run(Thread.java:679)
"PriorityThread_3" prio=10 tid=0x00007ff7e4061000 nid=0x12df runnable [0x00007ff7e2c69000]
java.lang.Thread.State: RUNNABLE
at ch.mypackage.CountingRunnable.run(CountingRunnable.java:17)
at java.lang.Thread.run(Thread.java:679)
"PriorityThread_2" prio=10 tid=0x00007ff7e405d000 nid=0x12de runnable [0x00007ff7e2d6a000]
java.lang.Thread.State: RUNNABLE
at ch.mypackage.CountingRunnable.run(CountingRunnable.java:17)
at java.lang.Thread.run(Thread.java:679)
"PriorityThread_1" prio=10 tid=0x00007ff7e4049800 nid=0x12dd runnable [0x00007ff7e2e6b000]
java.lang.Thread.State: RUNNABLE
at ch.mypackage.CountingRunnable.run(CountingRunnable.java:17)
at java.lang.Thread.run(Thread.java:679)
Si hago lo mismo en una máquina con Windows, los valores prio son los correctos, de acuerdo con las asignaciones de prioridad que encontré aquí.
Entonces, ¿es esto un error en jstack o estoy haciendo algo mal?
Si ejecuto "top | grep java" obtengo lo siguiente:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3394 root 20 0 4444m 15m 8376 S 789 0.1 0:47.52 java
lo que implica que el subproceso principal tiene una prioridad de 20, mientras que "top -H | grep java" da como resultado el siguiente resultado:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3457 root 15 -5 4444m 15m 8384 R 99 0.1 0:08.60 java
3456 root 16 -4 4444m 15m 8384 R 97 0.1 0:08.41 java
3455 root 17 -3 4444m 15m 8384 R 93 0.1 0:08.42 java
3454 root 18 -2 4444m 15m 8384 R 97 0.1 0:08.27 java
3453 root 19 -1 4444m 15m 8384 R 97 0.1 0:07.50 java
3452 root 20 0 4444m 15m 8384 R 51 0.1 0:07.44 java
3451 root 21 1 4444m 15m 8384 R 35 0.1 0:04.83 java
3450 root 22 2 4444m 15m 8384 R 99 0.1 0:04.78 java
3449 root 23 3 4444m 15m 8384 R 95 0.1 0:07.47 java
3448 root 24 4 4444m 15m 8384 R 18 0.1 0:02.85 java
lo que muestra que las prioridades de subprocesos de Java realmente afectan las prioridades de los subprocesos del sistema operativo.
Pero, ¿de dónde tiene jstack un valor de 10 en prio = 10? ¿Es solo un valor arbitrario?
2 Respuestas
0
La prioridad de subprocesos en Java es un tema muy, muy delicado... Puede encontrar una publicación interesante en StackOverlow aquí: https://stackoverflow.com/a/2170304/1343096
Básicamente intente cambiar su política de prioridad a 42:
-XX:ThreadPriorityPolicy=42
¡Háganos saber si funciona para usted!
Puedes encontrar todas las explicaciones siguiendo el enlace.
contestado el 23 de mayo de 17 a las 13:05
0
La Documentos de Java 7 estado
NOTA - Esta utilidad no es compatible y puede o no estar disponible en futuras versiones de JDK.
Así que asumiría que la salida de jstack
puede no ser exacto ya que los detalles de implementación en Linux pueden haber cambiado.
Los valores informados por htop -H
están en línea con este artículo, que incluyó en su pregunta, y son aquellos en los que se programan los procesos de Java dentro del kernel de Linux.
Si necesita asignar la salida de jstack a los subprocesos informados por top -H
solo necesitas convertir el nid
del jstack
a decimal o el pid
del top -H
al maleficio. Ver este articulo
Con respecto a su código fuente: el programa no terminaría cuando lo ejecuto. Tres sugerencias al escribir código multitarea de producción:
- Si sabe que todo está hecho (como después de llamar
printCounts()
delmain
) no dude en utilizarSystem.exit(0);
asegurando así que todos los subprocesos estén terminados. - Si desea probar el comportamiento de su código durante la ejecución paralela, a menudo es bueno crear todos
Thread
s primero y hacer que funcionen sincrónicamente. Vocaciónawait()
en un compartidoCountDownLatch
orCyclicBarrier
como primera declaración del trabajador a menudo hará este truco lo suficientemente bien. - Aunque la
boolean
leer y escribir debe ser atómico según Tutorial de Java, recomendaría declarar variables desencadenantes como sugoOn
el campo sea volátil ya que esto también influye en cómo el compilador optimizará su código.
Usando cualquiera volatile
or System.exit(0)
su punto de referencia terminó normalmente.
respondido 03 mar '14, 23:03
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas java linux multithreading pthreads jstack or haz tu propia pregunta.
Tenga en cuenta que los subprocesos de Java no se corresponden necesariamente con los procesos/subprocesos del sistema (por ejemplo, podría ser una JVM de un solo proceso que realiza la programación internamente) y, por lo tanto, la prioridad del subproceso de Java no coincide necesariamente con la prioridad del subproceso del sistema operativo. - Thomas
Independientemente de si los subprocesos de Java se corresponden o no con los subprocesos del sistema operativo, los niveles de prioridad de Java no se especifican en ninguna parte para que sean numéricamente iguales a los niveles del sistema operativo. - user207421
@Thomas AFAIK, openJDK no utiliza subprocesos verdes en absoluto, sea cual sea la plataforma. - João Fernandes
véase también stackoverflow.com/questions/128039/… - andersoj