Priorities | CodeGuru

Priorities

Bruce Eckel’s Thinking in Java Contents | Prev | Next The priority of a thread tells the scheduler how important this thread is. If there are a number of threads blocked and waiting to be run, the scheduler will run the one with the highest priority first. However, this doesn’t mean that threads with lower […]

Written By
CodeGuru Staff
CodeGuru Staff
Mar 1, 2001
9 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

The


priority
of a thread tells the scheduler how important this thread is. If there are a
number of threads blocked and waiting to be run, the scheduler will run the one
with the highest priority first. However, this doesn’t mean that threads
with lower priority don’t get run (that is, you can’t get
deadlocked because of priorities). Lower priority threads just tend to run less
often.

You


can read the priority of a thread with

getPriority( )
and
change it with
setPriority( ).
The form of the prior “counter” examples can be used to show the
effect of changing the priorities. In this applet you’ll see that the
counters slow down as the associated threads have their priorities lowered:
//: Counter5.java
// Adjusting the priorities of threads
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
 
class Ticker2 extends Thread {
  private Button
    b = new Button("Toggle"),
    incPriority = new Button("up"),
    decPriority = new Button("down");
  private TextField
    t = new TextField(10),
    pr = new TextField(3); // Display priority
  private int count = 0;
  private boolean runFlag = true;
  public Ticker2(Container c) {
    b.addActionListener(new ToggleL());
    incPriority.addActionListener(new UpL());
    decPriority.addActionListener(new DownL());
    Panel p = new Panel();
    p.add(t);
    p.add(pr);
    p.add(b);
    p.add(incPriority);
    p.add(decPriority);
    c.add(p);
  }
  class ToggleL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      runFlag = !runFlag;
    }
  }
  class UpL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int newPriority = getPriority() + 1;
      if(newPriority > Thread.MAX_PRIORITY)
        newPriority = Thread.MAX_PRIORITY;
      setPriority(newPriority);
    }
  }
  class DownL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int newPriority = getPriority() - 1;
      if(newPriority < Thread.MIN_PRIORITY)
        newPriority = Thread.MIN_PRIORITY;
      setPriority(newPriority);
    }
  }
  public void run() {
    while (true) {
      if(runFlag) {
        t.setText(Integer.toString(count++));
        pr.setText(
          Integer.toString(getPriority()));
      }
      yield();
    }
  }
}
 
public class Counter5 extends Applet {
  private Button
    start = new Button("Start"),
    upMax = new Button("Inc Max Priority"),
    downMax = new Button("Dec Max Priority");
  private boolean started = false;
  private static final int SIZE = 10;
  private Ticker2[] s = new Ticker2[SIZE];
  private TextField mp = new TextField(3);
  public void init() {
    for(int i = 0; i < s.length; i++)
      s[i] = new Ticker2(this);
    add(new Label("MAX_PRIORITY = "
      + Thread.MAX_PRIORITY));
    add(new Label("MIN_PRIORITY = "
      + Thread.MIN_PRIORITY));
    add(new Label("Group Max Priority = "));
    add(mp);
    add(start);
    add(upMax); add(downMax);
    start.addActionListener(new StartL());
    upMax.addActionListener(new UpMaxL());
    downMax.addActionListener(new DownMaxL());
    showMaxPriority();
    // Recursively display parent thread groups:
    ThreadGroup parent =
      s[0].getThreadGroup().getParent();
    while(parent != null) {
      add(new Label(
        "Parent threadgroup max priority = "
        + parent.getMaxPriority()));
      parent = parent.getParent();
    }
  }
  public void showMaxPriority() {
    mp.setText(Integer.toString(
      s[0].getThreadGroup().getMaxPriority()));
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(!started) {
        started = true;
        for(int i = 0; i < s.length; i++)
          s[i].start();
      }
    }
  }
  class UpMaxL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int maxp =
        s[0].getThreadGroup().getMaxPriority();
      if(++maxp > Thread.MAX_PRIORITY)
        maxp = Thread.MAX_PRIORITY;
      s[0].getThreadGroup().setMaxPriority(maxp);
      showMaxPriority();
    }
  }
  class DownMaxL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int maxp =
        s[0].getThreadGroup().getMaxPriority();
      if(--maxp < Thread.MIN_PRIORITY)
        maxp = Thread.MIN_PRIORITY;
      s[0].getThreadGroup().setMaxPriority(maxp);
      showMaxPriority();
    }
  }
  public static void main(String[] args) {
    Counter5 applet = new Counter5();
    Frame aFrame = new Frame("Counter5");
    aFrame.addWindowListener(
      new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          System.exit(0);
        }
      });
    aFrame.add(applet, BorderLayout.CENTER);
    aFrame.setSize(300, 600);
    applet.init();
    applet.start();
    aFrame.setVisible(true);
  }
} ///:~ 
Ticker2

follows the form established earlier in this chapter, but there’s an extra


TextField

for displaying the priority of the thread and two more buttons for incrementing


and decrementing the priority.

Also


notice the use of


yield( )

,


which voluntarily hands control back to the scheduler. Without this the


multithreading mechanism still works, but you’ll notice it runs slowly


(try removing the call to


yield( )

!).


You could also call


sleep( )

,


but then the rate of counting would be controlled by the


sleep( )

duration instead of the priority.

The


init( )

in


Counter5

creates an array of 10


Ticker2

s;


their buttons and fields are placed on the form by the


Ticker2

constructor.


Counter5

adds


buttons to start everything up as well as increment and decrement the maximum


priority of the threadgroup. In addition, there are labels that display the


maximum and minimum priorities possible for a thread and a


TextField

to show the thread group’s maximum priority. (The next section will fully


describe thread groups.) Finally, the priorities of the parent thread groups


are also displayed as labels.

When


you press an “up” or “down” button, that


Ticker2

’s


priority is fetched and incremented or decremented accordingly.

When


you run this program, you’ll notice several things. First of all, the


thread group’s

default
priority is 5. Even if you decrement the maximum priority below 5 before
starting the threads (or before creating the threads, which requires a code
change), each thread will have a default priority of 5.

The


simple test is to take one counter and decrement its priority to one, and


observe that it counts much slower. But now try to increment it again. You can


get it back up to the thread group’s priority, but no higher. Now


decrement the thread group’s priority a couple of times. The thread


priorities are unchanged, but if you try to modify them either up or down


you’ll see that they’ll automatically pop to the priority of the


thread group. Also, new threads will still be given a default priority, even if


that’s higher than the group priority. (Thus the group priority is not a


way to prevent new threads from having higher priorities than existing ones.)

Finally,


try to increment the group maximum priority. It can’t be done. You can


only reduce thread group maximum priorities, not increase them.


Thread
groups

All


threads belong to a

thread
group. This can be either the default thread group or a group you explicitly
specify when you create the thread. At creation, the thread is bound to a group
and cannot change to a different group. Each application has at least one
thread that belongs to the system thread group. If you create more threads
without specifying a group, they will also belong to the system thread group.

Thread


groups must also belong to other thread groups. The thread group that a new one


belongs to must be specified in the constructor. If you create a thread group


without specifying a thread group for it to belong to, it will be placed under


the system thread group. Thus, all thread groups in your application will


ultimately have the system thread group as the parent.

The


reason for the existence of thread groups is hard to determine from the


literature, which tends to be confusing on this subject. It’s often cited


as “security reasons.” According to Arnold

&

Gosling,


[62]

“Threads within a thread group can modify the other threads in the group,


including any farther down the hierarchy. A thread cannot modify threads


outside of its own group or contained groups.” It’s hard to know


what “modify” is supposed to mean here. The following example shows


a thread in a “leaf” subgroup modifying the priorities of all the


threads in its tree of thread groups as well as calling a method for all the


threads in its tree.

//: TestAccess.java
// How threads can access other threads
// in a parent thread group
 
public class TestAccess {
  public static void main(String[] args) {
    ThreadGroup
      x = new ThreadGroup("x"),
      y = new ThreadGroup(x, "y"),
      z = new ThreadGroup(y, "z");
    Thread
      one = new TestThread1(x, "one"),
      two = new TestThread2(z, "two");
  }
}
 
class TestThread1 extends Thread {
  private int i;
  TestThread1(ThreadGroup g, String name) {
    super(g, name);
  }
  void f() {
    i++; // modify this thread
    System.out.println(getName() + " f()");
  }
}
 
class TestThread2 extends TestThread1 {
  TestThread2(ThreadGroup g, String name) {
    super(g, name);
    start();
  }
  public void run() {
    ThreadGroup g =
      getThreadGroup().getParent().getParent();
    g.list();
    Thread[] gAll = new Thread[g.activeCount()];
    g.enumerate(gAll);
    for(int i = 0; i < gAll.length; i++) {
      gAll[i].setPriority(Thread.MIN_PRIORITY);
      ((TestThread1)gAll[i]).f();
    }
    g.list();
  }
} ///:~ 

In


main( )

,


several


ThreadGroup

s


are created, leafing off from each other:


x

has no argument but its name (a


String

),


so it is automatically placed in the “system” thread group, while


y

is under


x

and


z

is under


y

.


Note that initialization happens in textual order so this code is legal.

Two


threads are created and placed in different thread groups.


TestThread1

doesn’t have a


run( )

method but it does have an


f( )

that modifies the thread and prints something so you can see it was called.


TestThread2

is a subclass of


TestThread1

and its


run( )

is fairly elaborate. It first gets the thread group of the current thread, then


moves up the heritage tree by two levels using


getParent( ).

(This is contrived since I purposely place the


TestThread2

object two levels down in the hierarchy.) At this point, an array of handles to


Thread

s


is created using the method


activeCount( )

to ask how many threads are in this thread group and all the child thread


groups. The


enumerate( )

method places handles to all of these threads in the array


gAll

,


then I simply move through the entire array calling the


f( )

method for each thread, as well as modifying the priority. Thus, a thread in a


“leaf” thread group modifies threads in parent thread groups.

The


debugging method


list( )

prints all the information about a thread group to standard output and is


helpful when investigating thread group behavior. Here’s the output of


the program:

java.lang.ThreadGroup[name=x,maxpri=10]
    Thread[one,5,x]
    java.lang.ThreadGroup[name=y,maxpri=10]
        java.lang.ThreadGroup[name=z,maxpri=10]
            Thread[two,5,z]
one f()
two f()
java.lang.ThreadGroup[name=x,maxpri=10]
    Thread[one,1,x]
    java.lang.ThreadGroup[name=y,maxpri=10]
        java.lang.ThreadGroup[name=z,maxpri=10]
            Thread[two,1,z]

Not


only does


list( )

print the class name of


ThreadGroup

or


Thread

,


but it also prints the thread group name and its maximum priority. For threads,


the thread name is printed, followed by the thread priority and the group that


it belongs to. Note that


list( )

indents the threads and thread groups to indicate that they are children of the


un-indented thread group.

You


can see that


f( )

is called by the


TestThread2
run( )

method, so it’s obvious that all threads in a group are vulnerable.


However, you can access only the threads that branch off from your own


system

thread group tree, and perhaps this is what is meant by “safety.”


You cannot access anyone else’s system thread group tree.


Controlling
thread groups

Putting


aside the safety issue, one thing thread groups do seem to be useful for is


control: you can perform certain operations on an entire thread group with a


single command. The following example demonstrates this and the restrictions on


priorities within thread groups. The commented numbers in parentheses provide a


reference to compare to the output.

//: ThreadGroup1.java
// How thread groups control priorities
// of the threads inside them.
 
public class ThreadGroup1 {
  public static void main(String[] args) {
    // Get the system thread & print its Info:
    ThreadGroup sys =
      Thread.currentThread().getThreadGroup();
    sys.list(); // (1)
    // Reduce the system thread group priority:
    sys.setMaxPriority(Thread.MAX_PRIORITY - 1);
    // Increase the main thread priority:
    Thread curr = Thread.currentThread();
    curr.setPriority(curr.getPriority() + 1);
    sys.list(); // (2)
    // Attempt to set a new group to the max:
    ThreadGroup g1 = new ThreadGroup("g1");
    g1.setMaxPriority(Thread.MAX_PRIORITY);
    // Attempt to set a new thread to the max:
    Thread t = new Thread(g1, "A");
    t.setPriority(Thread.MAX_PRIORITY);
    g1.list(); // (3)
    // Reduce g1's max priority, then attempt
    // to increase it:
    g1.setMaxPriority(Thread.MAX_PRIORITY - 2);
    g1.setMaxPriority(Thread.MAX_PRIORITY);
    g1.list(); // (4)
    // Attempt to set a new thread to the max:
    t = new Thread(g1, "B");
    t.setPriority(Thread.MAX_PRIORITY);
    g1.list(); // (5)
    // Lower the max priority below the default
    // thread priority:
    g1.setMaxPriority(Thread.MIN_PRIORITY + 2);
    // Look at a new thread's priority before
    // and after changing it:
    t = new Thread(g1, "C");
    g1.list(); // (6)
    t.setPriority(t.getPriority() -1);
    g1.list(); // (7)
    // Make g2 a child Threadgroup of g1 and
    // try to increase its priority:
    ThreadGroup g2 = new ThreadGroup(g1, "g2");
    g2.list(); // (8)
    g2.setMaxPriority(Thread.MAX_PRIORITY);
    g2.list(); // (9)
    // Add a bunch of new threads to g2:
    for (int i = 0; i < 5; i++)
      new Thread(g2, Integer.toString(i));
    // Show information about all threadgroups
    // and threads:
    sys.list(); // (10)
    System.out.println("Starting all threads:");
    Thread[] all = new Thread[sys.activeCount()];
    sys.enumerate(all);
    for(int i = 0; i < all.length; i++)
      if(!all[i].isAlive())
        all[i].start();
    // Suspends & Stops all threads in 
    // this group and its subgroups:
    System.out.println("All threads started");
    sys.suspend(); // Deprecated in Java 1.2
    // Never gets here...
    System.out.println("All threads suspended");
    sys.stop(); // Deprecated in Java 1.2
    System.out.println("All threads stopped");
  }
} ///:~ 

The


output that follows has been edited to allow it to fit on the page (the


java.lang.

has been removed) and to add numbers to correspond to the commented numbers in


the listing above.

(1) ThreadGroup[name=system,maxpri=10]
      Thread[main,5,system]
(2) ThreadGroup[name=system,maxpri=9]
      Thread[main,6,system]
(3) ThreadGroup[name=g1,maxpri=9]
      Thread[A,9,g1]
(4) ThreadGroup[name=g1,maxpri=8]
      Thread[A,9,g1]
(5) ThreadGroup[name=g1,maxpri=8]
      Thread[A,9,g1]
      Thread[B,8,g1]
(6) ThreadGroup[name=g1,maxpri=3]
      Thread[A,9,g1]
      Thread[B,8,g1]
      Thread[C,6,g1]
(7) ThreadGroup[name=g1,maxpri=3]
      Thread[A,9,g1]
      Thread[B,8,g1]
      Thread[C,3,g1]
(8) ThreadGroup[name=g2,maxpri=3]
(9) ThreadGroup[name=g2,maxpri=3]
(10)ThreadGroup[name=system,maxpri=9]
      Thread[main,6,system]
      ThreadGroup[name=g1,maxpri=3]
        Thread[A,9,g1]
        Thread[B,8,g1]
        Thread[C,3,g1]
        ThreadGroup[name=g2,maxpri=3]
          Thread[0,6,g2]
          Thread[1,6,g2]
          Thread[2,6,g2]
          Thread[3,6,g2]
          Thread[4,6,g2]
Starting all threads:
All threads started

All


programs have at least one thread running, and the first action in


main( )

is to call the


static

method of


Thread

called


currentThread( )

.


From this thread, the thread group is produced and


list( )

is called for the result. The output is:

(1) ThreadGroup[name=system,maxpri=10]
      Thread[main,5,system]

You


can see that the name of the main thread group is


system

,


and the name of the main thread is


main

,


and it belongs to the


system

thread group.

The


second exercise shows that the


system

group’s maximum priority can be reduced and the


main

thread can have its priority increased:

(2) ThreadGroup[name=system,maxpri=9]
      Thread[main,6,system]

The


third exercise creates a new thread group,


g1

,


which automatically belongs to the


system

thread group since it isn’t otherwise specified. A new thread


A

is


placed in


g1

.


After attempting to set this group’s maximum priority to the highest


level and


A

’s


priority to the highest level, the result is:

(3) ThreadGroup[name=g1,maxpri=9]
      Thread[A,9,g1]

Thus,


it’s not possible to change the thread group’s maximum priority to


be higher than its parent thread group.

The


fourth exercise reduces


g1

’s


maximum priority by two and then tries to increase it up to


Thread.MAX_PRIORITY

.


The result is:

(4) ThreadGroup[name=g1,maxpri=8]
      Thread[A,9,g1]

You


can see that the increase in maximum priority didn’t work. You can only


decrease a thread group’s maximum priority, not increase it. Also, notice


that thread


A

’s


priority didn’t change, and now it is higher than the thread


group’s maximum priority. Changing a thread group’s maximum


priority doesn’t affect existing threads.

The


fifth exercise attempts to set a new thread to maximum priority:

(5) ThreadGroup[name=g1,maxpri=8]
      Thread[A,9,g1]
      Thread[B,8,g1]

The


new thread cannot be changed to anything higher than the maximum thread group


priority.

The


default thread priority for this program is 6; that’s the priority a new


thread will be created at and where it will stay if you don’t manipulate


the priority. Exercise six lowers the maximum thread group priority below the


default thread priority to see what happens when you create a new thread under


this condition:

(6) ThreadGroup[name=g1,maxpri=3]
      Thread[A,9,g1]
      Thread[B,8,g1]
      Thread[C,6,g1]

Even


though the maximum priority of the thread group is 3, the new thread is still


created using the default priority of 6. Thus, maximum thread group priority


does not affect default priority. (In fact, there appears to be no way to set


the default priority for new threads.)

After


changing the priority, attempting to decrement it by one, the result is:

(7) ThreadGroup[name=g1,maxpri=3]
      Thread[A,9,g1]
      Thread[B,8,g1]
      Thread[C,3,g1]

Only


when you attempt to change the priority is the thread group’s maximum


priority enforced.

A


similar experiment is performed in (8) and (9), in which a new thread group


g2

is


created as a child of


g1

and its maximum priority is changed. You can see that it’s impossible for


g2

’s


maximum to go higher than


g1

’s:

(8) ThreadGroup[name=g2,maxpri=3]
(9) ThreadGroup[name=g2,maxpri=3]

Also


notice that


g2

is automatically set to the thread group maximum priority of


g1

as


g2

is created.

After


all of these experiments, the entire system of thread groups and threads is


printed out:

(10)ThreadGroup[name=system,maxpri=9]
      Thread[main,6,system]
      ThreadGroup[name=g1,maxpri=3]
        Thread[A,9,g1]
        Thread[B,8,g1]
        Thread[C,3,g1]
        ThreadGroup[name=g2,maxpri=3]
          Thread[0,6,g2]
          Thread[1,6,g2]
          Thread[2,6,g2]
          Thread[3,6,g2]
          Thread[4,6,g2]

So


because of the rules of thread groups, a child group must always have a maximum


priority that’s less than or equal to its parent’s maximum priority.

The


last part of this program demonstrates methods for an entire group of threads.


First the program moves through the entire tree of threads and starts each one


that hasn’t been started. For drama, the


system

group is then suspended and finally stopped. (Although it’s interesting


to see that


suspend( )

and


stop( )

work on entire thread groups, you should keep in mind that these methods are


deprecated in Java 1.2.

)
But when you suspend the
system
group you also suspend the
main
thread and the whole program shuts down, so it never gets to the point where
the threads are stopped. Actually, if you do stop the
main
thread it throws a
ThreadDeath
exception, so this is not a typical thing to do. Since
ThreadGroup
is inherited from
Object,
which contains the
wait( )
method, you can also choose to suspend the program for any number of seconds by
calling
wait(seconds
* 1000)
.
This must acquire the lock inside a synchronized block, of course.

The


ThreadGroup

class also has


suspend( )

and


resume( )

methods so you can stop and start an entire thread group and all of its threads


and subgroups with a single command. (Again,


suspend( )

and


resume( )

are deprecated in Java 1.2.

)

Thread


groups can seem a bit mysterious at first, but keep in mind that you probably


won’t be using them directly very often.



[62]
The
Java Programming Language

,


by Ken Arnold and James Gosling, Addison-Wesley 1996 pp 179.

Contents

|

Prev

|

Next
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.