by BehindJava

How are Java Thread priorities translated to an OS thread priority

Home » java » How are Java Thread priorities translated to an OS thread priority

This is a quick tutorial on how Java Thread priorities translated to an OS thread priority.

Java thread priorities do not map cleanly to OS thread priorities.

As a result, if your algorithm relies in any way on the details of thread priority mapping, then it is broken, since it will vary according to so many variables. Upgrading your JRE or applying a patch/service pack to your OS could break it, for example - and of course just running on a different OS will have consequences too.

Except in very unusual cases, using only two priorities will be sufficient - Normal and Low. Most work will be done in a Normal thread. Low priority should be reserved for threads that must not be allowed to starve the threads of Normal priority, instead just gobbling up and processor power not otherwise used.

While you can get more fine-grained than this if you choose, you need to be aware that any greater detail will likely be lost on the target platform.

Indeed, some priority levels can map to the same “native” priority level. Here’s the list (based on the Hotspot code in OpenJDK 6):

Solaris

  • 1 ⇒ 0
  • 2 ⇒ 32
  • 3 ⇒ 64
  • 4 ⇒ 96
  • 5 – 10 ⇒ 127

Of note is that on Solaris, you can’t raise the thread priority above normal, only lower it: the priority value for 5 is the same as any of the higher values.

Linux

  • 1 – 10 ⇒ 4 – -5 (nice values)

Of note is that on Linux, different thread priorities in Java do map to distinct priority values at native level.

Windows

  • 1 – 2 ⇒ THREADPRIORITYLOWEST
  • 3 – 4 ⇒ THREADPRIORITYBELOW_NORMAL
  • 5 – 6 ⇒ THREADPRIORITYNORMAL
  • 7 – 8 ⇒ THREADPRIORITYABOVE_NORMAL
  • 9 – 10 ⇒ THREADPRIORITYHIGHEST

I’m not so sure on Sun JVM on Linux. Wrote a quick Java proggy to spawn 10 threads with each priority and calculate pi (4*atan(1) method) with BigDecimals 500,000 times each, join on each thread and report the elapsed time for run method. Yeah, prob’ly not the best example, but keeping it basic.

$uname -r && grep bogomips /proc/cpuinfo
2.4.33.3
bogomips        : 4312.26
$java -version 2>&1 |head -1
Java version "1.6.0_01"
$javac T.java && java -Xmx32m T
1:3112
2:2636
3:2662
4:3118
5:2870
6:3319
7:3412
8:3304
9:3299
10:3069

Looks like not much of a deviation that one would expect! That was on a small virtual Linux machine. Let’s try it on a real slab just in case, this box is fairly active too with load averages rarely below 7, let’s just see how we schedule in an environment like this:

$uname -r && grep bogomips /proc/cpuinfo
2.6.9-67.ELsmp
bogomips        : 3992.93
bogomips        : 3990.00
$java -version 2>&1 |head -1
java version "1.4.2_14"
$javac T.java && java -Xmx32m T
1:63200
2:64388
3:62532
4:58529
5:62292
6:64872
7:64885
8:64584
9:61653
10:61575

Hmmm, not much of a variation here, don’t know if 1.4 even mapped threads over. Let’s try a windows box. I know that Windows has a fairly aggressive thread priority schema. Anything above normal anecdotaly consumes much more. As such, let’s bump up to 900,000 iterations in each thread:

C:\>java -version
java version "1.6.0_11"
C:\>java -Xmx32m T
1:12578
2:12625
3:11469
4:11453
5:10781
6:8937
7:10516
8:8406
9:9953
10:7391