Java thread dump prio value doesn't correspond with real thread priority on linux?
Asked Answered
D

2

8

I intend to use thread priorities within my Java code. The application shall run on my Linux system:

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

After some reading in the Web I start my test-application with the following command now:

sudo java -XX:+UseThreadPriorities -XX:ThreadPriorityPolicy=1 -jar ThreadPriorityTest.jar

The test-application consists of the following two classes:

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);
        }
    }
}

If I let the program count for one minute (NUM_MILLIS_TO_COUNT_FOR=1601000) then I get the following output:

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

According to this output the priorities seem to have the expected impact! But if I generate a thread dump with "jstack" or "kill -s QUIT", then I get the following output, which implies that EVERY THREAD HAS THE SAME PRIORITY(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)

If I do the same on a Windows machine, the prio values are the correct ones, according to the priority mappings I found here.

So, is this a bug in jstack, or am I doing something wrong?

If I execute "top | grep java" I get the following:

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 

which implies that the main Thread has a priority of 20, while "top -H | grep java" results in the following output:

 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

which shows that the java thread priorities really affect the priorities of the OS-threads.

But where does jstack have a value of 10 in prio=10 from? Is it just an arbitrary value?

Disarticulate answered 3/5, 2012 at 11:58 Comment(4)
Note that Java threads do not necessarily correspond to system processes/threads (it might be a single process JVM that does the scheduling internally, for example) and thus Java's thread priority does not necessarily match the OS thread priority.Tilbury
Regardless of whether or not Java threads do correspond to OS threads, the Java priority levels are nowhere specified to be numerically equal to the OS levels.Abridge
@Tilbury AFAIK, openJDK don't make use of green threads at all, whatever the platform.Ampulla
see also #128539Eluvium
C
0

Thread priority in Java are a very very sensitive subject... You can find an intersting post on StackOverlow here : https://stackoverflow.com/a/2170304/1343096

Basically try to change your priority policy to 42 :

-XX:ThreadPriorityPolicy=42

Let us know if it does the trick for you!

You can find all the explanations by following the link.

Chally answered 4/6, 2012 at 23:55 Comment(0)
L
0

The Java 7 docs state

NOTE - This utility is unsupported and may or may not be available in future versions of the JDK.

So I would assume that the output of jstack may not be accurate as the implementation details on linux may have changed.

The values reported by htop -H are in line with this article, which you included in your question, and are those upon which the java-processes are sheduled inside the linux kernel.

If you need to map the output of jstack to the threads reported by top -H you only need to convert the nid from jstack to decimal or the pid from top -H to hex. See this article

Regarding your source code: the programm would not terminte when I run it. Three hints when writing production multi-tasking code:

  • If you know everything is done (as after calling printCounts() from main) don't hesitate to use System.exit(0); therby ensuring all threads are terminated.
  • If you want to test your code for behaviour during parallel execution it is often good to create all Threads first and get them to work synchronously. Calling await() on a shared CountDownLatch or CyclicBarrier as first statement of the worker will often do this trick well enough.
  • While boolean read and write is to be atomic as per Java tutorial, I would recommend declaring trigger-variables like your goOn field to be volatile as this also influences how the compiler will optimize your code.

Using either volatile or System.exit(0) your benchmark terminated normally.

Leonilaleonine answered 3/3, 2014 at 23:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.