Problem:
How Java Thread priority works? Is it interpreted at all? In this post we’ll show how setting priorities affects threads execution.
Solution:
java.lang.Thread class have methods that allow to operate on thread priorities. setPriority(int) allow to change thread’s priority (usually from NORMAL_PRIORITY) to some other value.
In the following example we create 10 threads that are busy with some computation. We set MIN_PRIORITY to the first one and MAX_PRIORITY to the last one. See how it works on my machine (GNU/Linux):
package com.farenda.java.lang; public class ThreadPriority { private static class Counter extends Thread { private static int threads = 0; private int id = ++threads; private int loops = 100_000; private long startMillis; public Counter(long startMillis) { this.startMillis = startMillis; } @Override public void run() { if (id == 1) { setPriority(MIN_PRIORITY); } else if (id == 10) { setPriority(MAX_PRIORITY); } while (loops-- >= 0) { process(loops); Thread.yield(); } System.out.printf("Thread %d (priority %d) done after: %d%n", id, currentThread().getPriority(), System.currentTimeMillis() - startMillis); } private long process(int x) { int sum = 0; for (int i = 0; i < x; ++i) { sum += i * Math.PI; } return sum; } } public static void main(String[] args) { long startMillis = System.currentTimeMillis(); Counter[] counters = { new Counter(startMillis), new Counter(startMillis), new Counter(startMillis), new Counter(startMillis), new Counter(startMillis), new Counter(startMillis), new Counter(startMillis), new Counter(startMillis), new Counter(startMillis), new Counter(startMillis) }; System.out.println("Starting counters:"); for (Counter c : counters) { c.start(); } System.out.println("Main thread done after: " + (System.currentTimeMillis() - startMillis)); } } [/sourcecode] <p> Running the code produces the following output: </p> Starting counters: Main thread done after: 55 Thread 3 (priority 5) done after: 56854 Thread 1 (priority 1) done after: 86493 Thread 2 (priority 5) done after: 87332 Thread 7 (priority 5) done after: 89398 Thread 10 (priority 10) done after: 91851 Thread 4 (priority 5) done after: 97830 Thread 9 (priority 5) done after: 102316 Thread 5 (priority 5) done after: 104185 Thread 8 (priority 5) done after: 109207 Thread 6 (priority 5) done after: 113975
I run that code a few times and always one thread finished much sooner than others. Here’s result of running the same code, but without Thread.yield():
Starting counters: Main thread done after: 100 Thread 5 (priority 5) done after: 57121 Thread 10 (priority 10) done after: 84208 Thread 3 (priority 5) done after: 87978 Thread 7 (priority 5) done after: 90503 Thread 8 (priority 5) done after: 94611 Thread 9 (priority 5) done after: 97762 Thread 2 (priority 5) done after: 100027 Thread 6 (priority 5) done after: 104389 Thread 4 (priority 5) done after: 106396 Thread 1 (priority 1) done after: 109485
As you can see there is really no difference.
And another run, but this time, when all threads but one have been set to MIN_PRIORITY:
Starting counters: Main thread done after: 12 Thread 5 (priority 1) done after: 57951 Thread 2 (priority 1) done after: 88227 Thread 6 (priority 1) done after: 93241 Thread 4 (priority 1) done after: 94999 Thread 10 (priority 10) done after: 99805 Thread 3 (priority 1) done after: 100993 Thread 7 (priority 1) done after: 104988 Thread 9 (priority 1) done after: 107884 Thread 8 (priority 1) done after: 110126 Thread 1 (priority 1) done after: 112575
Setting thread priority doesn’t mean that Thread Scheduler will run thread with the highest priority. It all depends on underlaying platform and is not portable.
Moreover Thread.yield and Thread.setPriority are merely hints to the Thread Scheduler and can be ignored by it! To quote “Effective Java, 2nd” by Josh Bloch: Thread priorities are among the least portable features of the Java platform.