java.lang.Thread

As everything in Java (well, almost) is object, if we want to start a new thread, we will need a class that represents the thread. This class is java.lang.Thread built into the JDK. When you start a Java code, the JVM automatically creates a few Thread objects and uses them to run different tasks that are needed by it. If you start up VisualVM, you can select the Threads tab of any JVM process and see the actual threads that are in the JVM. For example, the VisualVM as I started it has 29 live threads. One of them is the thread named main. This is the one that starts to execute the main method (surprise!). The main thread started most of the other threads. When we want to write a multithread application, we will have to create new Thread objects and start them. The simplest way to do that is new Thread(), and then calling the start method on the thread. It will start a new Thread that will just finish immediately as we did not give it anything to do. The Thread class, as it is in the JDK, does not do our business logic. The following are the two ways to specify the business logic:

  • Creating a class that implements the Runnable interface
  • Creating a class that extends the Thread class and overrides the run method

The following block of code is a very simple demonstration program:

public class ThreadIntermingling { 
static class MyThread extends Thread {
private final String name;
MyThread(String name){
this.name = name;
}
@Override
public void run(){
for(int i = 1 ; i < 1000 ; i ++ ){
System.out.print(name + " " + i+ ", ");
}
}
}
public static void main(String[] args){
Thread t1 = new MyThread("t1");
Thread t2 = new MyThread("t2");
t1.start();
t2.start();
System.out.print("started ");

}
}

The preceding code creates two threads and starts them one after the other. When the start method is called, it schedules the thread object to be executed and then returns. As a result, the new thread will soon start executing asynchronously while the calling thread continues its execution. The two threads, and the main thread, run parallel in the following example and create an output that looks something like this:

started t2 1, t2 2, t2 3, t2 4, t2 5, t2 6, t2 7, t2 8, t1 1, t2 9, t2 10, t2 11, t2 12,...

The actual output changes from run to run. There is no definite order of the execution or how the threads get access to the single screen output. There is not even guarantee that in each and every execution, the message started is printed before any of the thread messages.

To get a better understanding of this, we will have to look at the state diagram of threads. A Java Thread can be in one of the following states:

  • NEW
  • RUNNABLE
  • BLOCKED
  • WAITING
  • TIMED_WAITING
  • TERMINATED

These states are defined in the enumThread.State. When you create a new thread object, it is in the NEW state. At this moment, the thread is nothing special, it is just an object but the operating system execution-scheduling does not know about it. In some sense, it is only a piece of memory allocated by the JVM.

When the start method is invoked, the information about the thread is passed to the operating system and the OS schedules the thread so it can be executed by it when there is an appropriate time slot. Doing this is a resourceful action and that is the reason why we do not create and, especially, do not start new Thread objects only when it is needed. Instead of creating new Threads, we will keep the existing threads for a while, even if they are not needed at the moment, and reuse an existing one if there is one suitable.

A thread in the OS can also be in a running state as well as runnable when the OS schedules and executes it at the moment. Java JDK API does not distinguish between the two for good reason. It would be useless. When a thread is in the RUNNABLE state asking if it is actually running from the thread itself, it will result in an obvious answer: if the code just returned from the getState method implemented in the Thread class, then it runs. If it were not running, it would not have returned from the call in the first place. If the getState method was called from another thread, then the result about the other thread by the time the method returns would be meaningless. The OS may have stopped, or started, the queried thread several times until then.

A thread is in a BLOCKED state when the code executing in the thread tries to access some resource that is not currently available. To avoid constant polling of resources, the operating system provides effective notification mechanism so the threads get back to the RUNNABLE state when the resource they need becomes available.

A thread is in the WAIT or TIMED_WAITING state when it waits for some other thread or lock. TIMED_WAITING is the state when the waiting started calling a version of a method that has timeout.

Finally, the TERMINATED state is reached when the thread finishes its execution. If you append the following lines to the end of our previous example, then you will get a TERMINATED printout and also an exception thrown up to the screen complaining about illegal thread state, which is because you cannot start an already terminated thread:

System.out.println(); 
System.out.println(t1.getState());
System.out.println();
t1.start();

Instead of extending the Thread class to define what to execute asynchronously, we can create a class that implements Runnable. Doing that is more in line with the OO programming approach. The something that we implement in the class is not a functionality of a thread. It is more of a something that can be executed. It is something that can just run.

If this execution is asynchronous in a different thread, or it is executed in the same thread that was calling the run method, is a different concern that has to be separated. If we do it that way, we can pass the class to a Thread object as a constructor argument. Calling start on the Thread object will start the run method of the object we passed. This is not the gain. The gain is that we can also pass the Runnable object to an Executor (dreadful name, huhh!). Executor is an interface, and implementations execute Runnable (and also Callable, see later) objects in Threads in an efficient way. Executors usually have a pool of Thread objects that are prepared, and in the BLOCKED state. When the Executor has a new task to execute, it gives it to one of the Thread objects and releases the lock that is blocking the thread. The Thread gets into the RUNNABLE state, executes the Runnable, and gets blocked again. It does not terminate and thus can be reused to execute another Runnable later. That way, Executors avoid the resource consuming process of thread registration into the operating system.

Professional application code never creates a new Thread. Application code uses some framework to handle the parallel execution of the code or uses Executors provided by some ExecutorService to start Runnable or Callable objects.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.188.238