Thread PrioritiesJ8 Home « Thread Priorities
In this lesson we investigate thread priorities and how we can have the priority set automatically by the invoking thread or assign thread priorities ourselves using methods of
the Thread
class. By setting a threads priority higher, we can hopefully make this thread receive more of our processors time than lower priority threads. Setting a threads
priority is no guarantee that the thread does in fact receive more CPU time as other factors such as waiting for resources may affect the higher priority threads performance. Also the way
the underlying operating system implements multitasking may also affect thread performance and a lower priority thread might under some conditions actually get more CPU time than
a higher priority thread. Generally speaking though, threads with higher priorities will get more CPU time than lower priority threads.
The priority ranges we can give a thread have to fall in the ranges of two class constants within the Thread
class, namely MIN_PRIORITY
and MAX_PRIORITY
. At the time of
writing these values are set to 1
and 10
respectively. We can also reassign a thread priority back to the default rating using the NORM_PRIORITY
value, which at the
time of writing has a value of 5
.
Thread
Methods Overview Top
The table below shows the declarations of the fields and methods of the Thread
class used in this lesson:
Field Declaration | Description |
---|---|
public static final int MIN_PRIORITY | Minimum priority a thread can have which is currently set at 1 . |
public static final int MAX_PRIORITY | Maximum priority a thread can have which is currently set at 10 . |
Method Declaration | Description |
public final int getPriority() | Return the priority of this thread. |
public final void join() | Waits for current thread to die. |
public void run() | If this thread was constructed using a subclass of the Thread class this method does nothing and should be overridden in the subclass.If this thread was constructed using a separate Runnable run object, then that Runnable object's run() method is called. |
public void start() | The JVM calls the run() method of this thread, so it can begin execution. |
public static void yield() | Will cause the currently executing thread to temporarily pause and allow other threads a chance to execute. |
We will go through the methods mentioned above in much greater detail as we go through this lesson. Use the links in the table above to go to the code example where the method is first used.
Same Thread Priority Example Top
To see the possible impact of prioritizing threads lets take a look at running multiple threads without any preset priorities. In this scenario all the threads will default to the thread
priority of the thread they were started from. As we are just creating these threads from the main user thread, all these threads will also be user threads and have a
default priority set, which is 5
.
package info.java8;
/*
Multiple threads with some counters to see which threads get the most CPU action
*/
public class TestNoPrioritySet implements Runnable {
static boolean finish = false;
int count = 0;
// Override run() method of Runnable interface to execute a new thread
public void run() {
do {
count++;
} while (finish == false && count < 9999);
finish = true; // Ensure we stop when first thread hits count
}
public static void main(String[] args) {
// Create 3 new Runnables
TestNoPrioritySet tnps1 = new TestNoPrioritySet();
TestNoPrioritySet tnps2 = new TestNoPrioritySet();
TestNoPrioritySet tnps3 = new TestNoPrioritySet();
// Create 3 new threads
Thread th1 = new Thread(tnps1);
Thread th2 = new Thread(tnps2);
Thread th3 = new Thread(tnps3);
// Check thread priorities
System.out.println("th1 thread priority = " + th1.getPriority());
System.out.println("th2 thread priority = " + th2.getPriority());
System.out.println("th3 thread priority = " + th3.getPriority());
th1.start();
th2.start();
th3.start();
// Join threads together
try {
th1.join();
th2.join();
th3.join();
} catch (InterruptedException ex) {
System.out.println(ex);
}
System.out.println("tnps1 count = " + tnps1.count);
System.out.println("tnps2 count = " + tnps2.count);
System.out.println("tnps3 count = " + tnps3.count);
}
}
Save, compile and run the TestNoPrioritySet
class in directory c:\_Concurrency in the usual way.
In the screenshot above we have run the program three times and the totals are fairly evenly spread between the three threads. All the threads inherit the thread priority from the main
thread which is set by the JVM
to the default which is 5
. We use the getPriority()
method to prove this and print the thread priorities out.
The totals you get out will certainly differ each time you run the programs and depend on several factors such as your CPU and how it deals with threads, what is running on your computer at the time and how the scheduler is set up.
As mentioned above thread priorities are no guarantee that a higher priority thread will get more CPU time so it is definitely inadvisable to base thread usage and your coding on priorities. You can of course use thread priorities to take advantage of priority scheduling if it is available, just don't rely on it.
Different Thread Priority Example Top
To see the possible impact of prioritizing threads lets take a look at running multiple threads where we set one thread to the smallest priority and another two to the maximum priority.
package info.java8;
/*
Multiple threads with some counters to see which threads get the most CPU action
*/
public class TestPriority implements Runnable {
static boolean finish = false;
int count = 0;
// Override run() method of Runnable interface to execute a new thread
public void run() {
do {
count++;
} while (finish == false && count < 9999);
finish = true; // Ensure we stop when first thread hits count
}
public static void main(String[] args) {
// Create 3 new Runnables
TestPriority tp1 = new TestPriority();
TestPriority tp2 = new TestPriority();
TestPriority tp3 = new TestPriority();
// Create 3 new threads
Thread th1 = new Thread(tp1);
Thread th2 = new Thread(tp2);
Thread th3 = new Thread(tp3);
// Set thread priorities
th1.setPriority(Thread.MIN_PRIORITY);
th2.setPriority(Thread.MAX_PRIORITY);
th3.setPriority(Thread.MAX_PRIORITY);
// Check thread priorities
System.out.println("th1 thread priority = " + th1.getPriority());
System.out.println("th2 thread priority = " + th2.getPriority());
System.out.println("th3 thread priority = " + th3.getPriority());
th1.start();
th2.start();
th3.start();
// Join threads together
try {
th1.join();
th2.join();
th3.join();
} catch (InterruptedException ex) {
System.out.println(ex);
}
System.out.println("tp1 count = " + tp1.count);
System.out.println("tp2 count = " + tp2.count);
System.out.println("tp3 count = " + tp3.count);
}
}
Save, compile and run the TestPriority
class in directory c:\_Concurrency in the usual way.
In the screenshot above we have run the program three times and the results are fairly inconsistent. On my machine I ran this program many times and there was no guarantee that the higher priority threads got any favourable CPU usage.
This program shows that thread priorities are no guarantee that a higher priority thread will get more CPU time so it is definitely inadvisable to base thread usage and code on thread priorities. You can of course use thread priorities to take advantage of priority scheduling if it is available, just don't rely on it.
The yield()
Method Top
The static yield()
method puts the currently running thread back to a runnable state to allow other threads of the same priority a chance to run. Although this sounds
a great way to use thread prioritisation and allow equal usage of the CPU in reality there is no guarantee that this will actually happen. What we can guarantee is that the yield()
method
puts the currently running thread back to a runnable state. After this happens which thread gets chosen by the scheduler is out of our hands and it is very possible that the
yielding thread is selected again and goes straight back to executing. Lets have a look at how we can use the yield()
method:
package info.java8;
/*
Multiple threads with some counters and yields to see which threads get the most CPU action
*/
public class TestPriorityYield implements Runnable {
static boolean stop = false;
int count = 0;
// Override run() method of Runnable interface to execute a new thread
public void run() {
do {
count++;
// Yield ON ALL threads
Thread.yield();
} while (stop == false && count < 9999);
stop = true; // Ensure we stop when first thread hits count
}
public static void main(String[] args) {
// Create 3 new Runnables
TestPriorityYield tpy1 = new TestPriorityYield();
TestPriorityYield tpy2 = new TestPriorityYield();
TestPriorityYield tpy3 = new TestPriorityYield();
// Create 3 new threads
Thread th1 = new Thread(tpy1, "th1");
Thread th2 = new Thread(tpy2, "th2");
Thread th3 = new Thread(tpy3, "th3");
// Set thread priorities
th1.setPriority(Thread.MIN_PRIORITY);
th2.setPriority(Thread.MAX_PRIORITY);
th3.setPriority(Thread.MAX_PRIORITY);
// Check thread priorities
System.out.println("th1 thread priority = " + th1.getPriority());
System.out.println("th2 thread priority = " + th2.getPriority());
System.out.println("th3 thread priority = " + th3.getPriority());
th1.start();
th2.start();
th3.start();
// Join threads together
try {
th1.join();
th2.join();
th3.join();
} catch (InterruptedException ex) {
System.out.println(ex);
}
System.out.println("tpy1 count = " + tpy1.count);
System.out.println("tpy2 count = " + tpy2.count);
System.out.println("tpy3 count = " + tpy3.count);
}
}
Save, compile and run the TestPriorityYield
class in directory c:\_Concurrency in the usual way.
In the screenshot above we have run the program three times and the totals are fairly evenly spread between the three threads. Even though we are using the yield()
method it seems to
make little difference to which thread becomes runnable after a thread has yielded control.
We will adjust the above code slightly to check the priority value and then yield for threads with a priority of 1
.
package info.java8;
/*
Multiple threads with some counters and yield on low priority thread only
*/
public class TestLowPriorityYield implements Runnable {
static boolean stop = false;
int count = 0;
// Override run() method of Runnable interface to execute a new thread
public void run() {
do {
count++;
// Yield on low priority thread ONLY
if (Thread.currentThread().getPriority() == 1) {
Thread.yield();
}
} while (stop == false && count < 9999);
stop = true; // Ensure we stop when first thread hits count
}
public static void main(String[] args) {
// Create 3 new Runnables
TestLowPriorityYield tlpy1 = new TestLowPriorityYield();
TestLowPriorityYield tlpy2 = new TestLowPriorityYield();
TestLowPriorityYield tlpy3 = new TestLowPriorityYield();
// Create 3 new threads
Thread th1 = new Thread(tlpy1, "th1");
Thread th2 = new Thread(tlpy2, "th2");
Thread th3 = new Thread(tlpy3, "th3");
// Set thread priorities
th1.setPriority(Thread.MIN_PRIORITY);
th2.setPriority(Thread.MAX_PRIORITY);
th3.setPriority(Thread.MAX_PRIORITY);
// Check thread priorities
System.out.println("th1 thread priority = " + th1.getPriority());
System.out.println("th2 thread priority = " + th2.getPriority());
System.out.println("th3 thread priority = " + th3.getPriority());
th1.start();
th2.start();
th3.start();
// Join threads together
try {
th1.join();
th2.join();
th3.join();
} catch (InterruptedException ex) {
System.out.println(ex);
}
System.out.println("tlpy1 count = " + tlpy1.count);
System.out.println("tlpy2 count = " + tlpy2.count);
System.out.println("tlpy3 count = " + tlpy3.count);
}
}
Save, compile and run the TestLowPriorityYield
class in directory c:\_Concurrency in the usual way.
In the screenshot above we have run the program three times and the totals for the higher priority threads are always higher. In this very contrived example we always yield on the 'th1' thread as
it is the only thread with a priority of 1
. In fact I ran this code many times and the 'th1' thread was always the lowest due to yielding. To do this we are relying on a threads
priority which isn't really a reliable or good practice. Thread priorities are no guarantee that a higher priority thread will get more CPU time so it is definitely inadvisable to base
thread usage and your code on priorities as we have done here.
Lesson 4 Complete
In this lesson we investigated thread priorities and how we can have the priority set automatically by the invoking thread or assign thread priorities ourselves using methods of the Thread
class.
What's Next?
In our final lesson of the section we explore how threads can communicate with each other when they are within a synchronized method or code block.