Main Page

Previous Next

Thread Priorities

All threads have a priority that determines which thread is executed when several threads are waiting for their turn. This makes it possible to give one thread more access to processor resources than another. Let's consider an elementary example of how this could be used. Suppose you have one thread in a program that requires all the processor resources – some solid long running calculation– and some other threads that require relatively few resources. By making the thread that requires all the resources a low priority thread, you ensure that the other threads get executed promptly, while the processor bound thread can make use of the processor cycles that are left over after the others have had their turn.

The possible values for thread priority are defined in static data members of the class Thread. These members are of type int, and are declared as final. The maximum thread priority is defined by the member MAX_PRIORITY, which has the value 10. The minimum priority is MIN_PRIORITY, defined as 1. The value of the default priority that is assigned to the main thread in a program is NORM_PRIORITY, which is set to 5. When you create a thread, its priority will be the same as that of the thread that created it.

You can modify the priority of a thread by calling the setPriority() method for the Thread object. This method accepts an argument of type int that defines the new priority for the thread. An IllegalArgumentException will be thrown if you specify a priority that is less than MIN_PRIORITY or greater than MAX_PRIORITY.

If you're going to be messing about with the priorities of the threads in your program, you need to be able to find out the current priority for a thread. You can do this by calling the getPriority() method for the Thread object. This will return the current priority for the thread as a value of type int.

Using Thread Priorities

In the last example, you could set priorities for the threads by adding statements to main():

clerk1Thread.setPriority(Thread.MIN_PRIORITY);     // Credits are a low priority
clerk2Thread.setPriority(Thread.MAX_PRIORITY);     // Debits are a high priority

You can put these statements following the call to the start() method for each of the Thread objects for the clerks. However, this can't have much effect in our program since one clerk can't get ahead of the other. This is because each clerk only queues one transaction and they are allocated alternately to each clerk.

In the interests of learning more about how thread priorities affect the execution of your program, let's change the example once more to enable a Clerk object to queue transactions. We can do this quite easily using a LinkedList object, which we discussed in Chapter 13. There are a couple of points to be aware of though.

The first point is that only the Vector class out of the collection classes is thread-safe – that is, safe for modification by more than one thread. For the others you must either only access them by methods and code blocks that are synchronized on the collection object, or wrap the collection class in a thread-safe wrapper. Let's change the example to incorporate the latter.

The second point is that whether thread priorities have any effect depends on your operating system. If it doesn't support thread priorities, then setting thread priorities in your Java code will have no effect. Let's run it anyway to see how it works.

Try It Out – Setting Thread Priorities

We can extend the Clerk class to handle a number of Transaction objects by giving the in-tray the capacity to store several transactions in a list, but not too many – we don't want to overwork the clerks.

The Collections class provides methods for creating synchronized sets, lists, and maps from unsynchronized objects. The static synchronizedList() method in the Collections class accepts an argument that is a list and returns a List object that is synchronized. We can use this to make our inTray a synchronized list for storing transactions.

import java.util.List;
import java.util.Collections;
import java.util.LinkedList;

public class Clerk implements Runnable {
  Bank theBank;
  // The in-tray holding transactions
  private List inTray = Collections.synchronizedList(new LinkedList());

  private int maxTransactions = 8;      // Maximum transactions in the in-tray

  // Constructor
  public Clerk(Bank theBank) {
    this.theBank = theBank;                  // Who the clerk works for
    //inTray     = null;                //Commented out: don't need this now
// Plus the rest of the class...

Note that we have deleted the statement from the constructor that originally set inTray to null. Now that we are working with a list, we must change the doTransaction() method in the Clerk class to store the transaction in the list as long as the tray is not full or, to say it another way, there are less than maxTransactions in the list. Here's the revised code to do this:

synchronized public void doTransaction(Transaction transaction) {
  while(inTray.size() >= maxTransactions) {
    try {

    } catch(InterruptedException e) {

The size() method for the list returns the number of objects it contains so checking this is trivial. We use the add() method to add a new Transaction object to the end of the list.

The run() method for a clerk retrieves objects from the in-tray so we must update that to deal with a list:

  synchronized public void run() {
    while(true) {
      while(inTray.size() == 0) {   // No transaction waiting?
        try {
          wait();                   // Then take a break until there is

        } catch(InterruptedException e) {
      notifyAll();                  // Notify other threads locked on this clerk

The remove()method in the List interface that we are using here removes the object at the index position in the list specified by the argument and returns a reference to it. Since we use 0 as the index we retrieve the first object in the list to pass to the doTransaction() method for the Bank object.

Since we now use a list to store transactions, the isBusy() method for a Clerk object also needs to be changed:

synchronized public void isBusy() {
  while(inTray.size() != 0) {           // Is this object busy?
    try {
      wait();                       // Yes, so wait for notify call

    } catch(InterruptedException e) {
  return;                           // It is free now

Now the clerk is not busy if there are no transactions in the inTray list. Hence we test the value returned by size().

That's all we need to buffer transactions in the in-tray of each clerk. If you reactivate the output statements that we added to the method in the Bank class, you'll be able to see how the processing of transactions proceeds.

With the priorities set by the calls to setPriority() we saw earlier, the processing of credits should run ahead of the processing of debits, although the fact that the time to process a debit is longer than the time for a credit will also have a significant effect. To make the thread priority the determining factor, set the times in the calls to the sleep() method in the Bank class to the same value. You could then try changing the values for priorities around to see what happens to the sequence in which transactions are processed. Of course, if your operating system does not support priority scheduling, then it won't have any effect anyway.

How It Works

We've made the inTray object a synchronized LinkedList, by passing it to the static synchronizedList() method in the Collections class. This method returns a thread-safe List based on the original LinkedList object. We use the thread-safe List object to store up to maxTransactions transactions – eight in this case. The doTransaction() method for a Clerk object makes sure that a transaction is only added to the list if there are less than eight transactions queued.

The doTransaction() method for the Bank object always obtains the first object in the List, so the transactions will be processed in the sequence in which they were added to the list.

If your operating system supports priority scheduling, altering the thread priority values will change the pattern of servicing of the transactions.

Previous Next
JavaScript Editor Java Tutorials Free JavaScript Editor