How does thread scheduling work in Java?

First off, why is thread scheduling even necessary? Well, simply because there typically are more threads than there are CPU’s. This means that the threads must share the CPU.

When scheduling threads, the Java virtual machine (JVM) decides which thread gets to run on the CPU. The Java language does not does not guarantee that a certain scheduling algorithm must be used – the algorithm used for thread scheduling is determined by the implementer of the virtual machine. Remember that there are multiple implementations of the Java virtual machine. Most virtual machines simply choose the highest priority runnable thread to run, but this is not guaranteed.

A “greedy” thread can ruin user experience

Every virtual machine has a different degree of scheduling sophistication. Some virtual machines might not preempt a thread that has been running for a long time. This means that a greedy thread could potentially keep the CPU until it voluntarily gives up control by making a blocking method call. Of course, this means that a greedy thread can be bad for system performance because other important threads might not get the CPU time that they need. For example, if there is a thread that monitors user input but does not get to run on a regular basis (because there is a “greedy” thread), the user may think that the program is unresponsive.

Threads should cooperate with each other

In order to ensure equitable distribution of CPU time, threads should cooperate. Any thread that performs a long calculation should call the yield method. Calling yield means that control will go back to the virtual machine. Then the virtual machine can run its scheduling algorithm and determine which thread gets the CPU. If no other threads are waiting, then yield will return immediately and the original thread will get to resume its task.

The Java Thread class

The Java language and library provide a lot of support for multithreaded programming.
In the package java.lang there is a Thread class which represents a thread of execution.

How to use thread

To use Thread there are two things you need to do: 1. Create an instance with new and 2. Call the start method

This is what that would look like:

//create the thread
Thread t = new Thread();

t.start();

The call to start returns immediately which means that the original thread can continue execution. This also means that the new thread can begin execution too.

The Thread run method

The work that is done by a thread is done in the run method. The run method will be called automatically when the start method is called.

There is an implementation of the run method in the Thread class, but it does nothing – here’s what it looks like:

public class Thread implements Runnable
{
  public void run()
  {
    ...  //does nothing by default

  }
  ...
}

Also note that the call to start will result in a call to the run method – which, to repeat, does nothing by default.

//create the thread
Thread t = new Thread();

//this call will automatically call the run method:
t.start();

How to provide a run method

If, by default, the run method does nothing then how can a programmer provide their own implementation of the run method? Naturally, you would want a thread to execute a task that you define. Well, there are two options to provide a run method, and define the work that a thread must do:

1. You can extend the library Thread class and override the empty implementation with your own version.

2. You can provide a separate class that implements the Runnable interface and that class contains a run method.

Extending the Thread class example

class Koala extends Thread
{
  public void run()
  {
    System.out.println("climb"); 
  }
}

Overriding the run method and extending the Thread class is pretty straightforward and easy. Because of dynamic binding, the correct version of the run method will be called – the one defined by the programmer in the derived class. And, usually no other methods need to be overridden either.

And here is what it would look like if you want to use the class that extends Thread:

Thread someThread = new Koala();

//this will invoke Koala's run method:
someThread.start();

So, to use a class which extends Thread you just have to create an object of the class and then invoke the inherited start method. The overridden version of run will be called asynchronously.

Implementing the Runnable interface

Let’s talk more about the second way to provide a run method. This is done by creating a separate class which implements the Runnable interface. Then, the code for the run method is provided by that class.

Here is what the Runnable interface looks like:

public interface Runnable
{

  public void run();

}

And here is what a class that implements Runnable would look like:

class Koala implements Runnable
{
  public void run()
  {
    System.out.println("climb"); 
  }
}

So, a run method can be provided by simply creating a separate class that implements the Runnable interface. Note that the Runnable interface contains only the run method, and no other methods.

Also note that the Thread class also implements the Runnable interface because Runnable is where the signature of the run method is defined.





Follow Varoon Sahgal, author, on Google Plus