Java threading introduction Thread-safety Thread methods Interruption Thread scheduling Context switching Thread priorities sleep() yield() Deadlock Threading with Swing invokeLater() Thread pools CoundDownLatch ThreadPoolExecutor CyclicBarrier
What is Java thread priority?
In our introduction to thread priority, we pointed out some problems with the system, notably differences between what priority actually means on different systems. Here, we'll look at how thread priority is actually implemented in Windows and Linux.
In the Hotspot VM for Windows, setPriority() map to Windows relative priorities (set by the SetThreadPriority() API call). The actual mappings were changed between Java 5 and Java 6 as follows:
Figure 1. Approximate CPU allocation against thread priority under Windows XP on a uniprocessor machine. Results for Vista on a dual core machine are very similar.
Figure 2. Approximate CPU allocation against thread priority on a uniprocessor machine under Debian Linux (kernel 2.6.18).
In effect, the priority mappings were 'shifted down' to avoid THREAD_PRIORITY_TIME_CRITICAL, apparently following reports that this setting could affect vital processes such as audio. Note that there is really no such mapping to THREAD_PRIORITY_IDLE as suggested by Oaks & Wong (they were possibly misinterpreting a dummy value that appears at the beginning of the priority mapping table in the VM source code).
On Windows, thread priority is a key element in deciding which thread gets scheduled, although the overall priority of a thread is a combination of the process's priority class, the thread's relative priority (values from the table above), plus any temporary "boost" given in specific circumstances (such as on returning from a wait on I/O). But in general:
Lower-priority threads are given CPU when all higher priority threads are waiting (or otherwise unable to run) at that given moment.
The actual proprtion of CPU allotted to a thread therefore depends on how often that situation occurs— there's no relation per se between priority and CPU allocation. Now of course, if this was literally the be-all and end-all to thread scheduling, then there'd quite possibly be lower-priority threads that barely got any CPU at all, being continually starved by higher-priority threads that needed CPU. So Windows has a fallback mechanism, whereby a thread that hasn't run for a long time is given a temporary priority boost. (For more details about some of the points mentioned here, see the section on thread scheduling.)
What this generally means is that on Windows:
Thread priority isn't very meaningful when all threads are competing for CPU.
As an illustration, Figure 1 opposite shows the results of an experiment in which ten threads are run concurrently, one thread with each Java priority. Each thread sits in a CPU-intensive loop (continually a random number using a XORShift generator). Each thread keeps a count of how many numbers it has generated1. After a certain period (60 seconds in this case), all threads are told to stop and queried to find out how many numbers they generated; the number generated is taken as an indication of the CPU time allocated to that thread2. As can be seen, thread priorities 1-8 end up with a practically equal share of the CPU, whilst priorities 9 and 10 get a vastly greater share (though with essentially no difference between 9 and 10). The version tested was Java 6 Update 10. For what it's worth, I repeated the experiment on a dual core machine running Vista, and the shape of the resulting graph is the same. My best guess for the special behaviour of priorities 9 and 10 is that THREAD_PRIORITY_HIGHEST in a foreground window has just enough priority for certain other special treatment by the scheduler to kick in (for example, threads of internal priority 14 and above have their full quantum replenished after a wait, whereas lower priorities have them reduced by 1).
Under Linux, you have to go through more hoops to get thread priorities to function at all, although in the end, they may be more useful than under Windows. In Linux:
The rationale behind requiring root privileges to alter thread priorities largely eludes me. Whether or not Linux itself generally should place such a restriction on changing nice values is arguable, bit since it doesn't, it seems odd to add it to the JVM (as opposed to, say, building in a restriction via the Java SecurityManager). And does anyone really run, say, their web server as root?
Assuming you go through these steps to enable them, Java thread priorities in Hotspot map to nice values. Unlike Windows priorities, Linux nice values are used as a target for CPU allocation (although like Windows, recent versions of Linux— from kernel 2.6.8 onwards— also apply various heuristics to temporarily boost or penalise threads). The mappings from Java priorities to Linux nice values are given in the table opposite. Note that:
Figure 2 shows the results of the thread priority experiment repeated under Linux with kernel 2.6.18. The different coloured traces simply represent 3 separate runs of the experiment. The graph shows that there is a correlation between Java priority (nice value) and CPU allocation, although it is far from linear.
Sun have published more detailed information on Solaris thread priorities.
1. To reduce the number of memory writes, each thread actually incremented the counter
when the bottom 7 bits of the random number generated were all set. However, this should not
affect the test, since millions of numbers were generated by each thread, and the bits of numbers
generated by XORShift are generally considered equally random.
Copyright © Javamex UK 2014. All rights reserved.