¿El valor prio de volcado de subprocesos de Java no se corresponde con la prioridad de subprocesos reales en Linux?

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?

preguntado el 03 de mayo de 12 a las 12:05

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. -

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. -

@Thomas AFAIK, openJDK no utiliza subprocesos verdes en absoluto, sea cual sea la plataforma. -

2 Respuestas

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

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() del main) no dude en utilizar System.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 Threads primero y hacer que funcionen sincrónicamente. Vocación await() en un compartido CountDownLatch or CyclicBarrier 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 su goOn 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 or haz tu propia pregunta.