COP3338 - Advanced Programming

Thread Class


java.lang.Thread.java;

Threads - Concurrent Processing 


Creating Thread

Implementing Runnable Interface ---->Example

Extending Thread Class ------------->Example

Thread Synchronization ------------->Example -  Non-synchronized Thread

Monitor

Synchronized Methods --------------->Example

Synchronized Blocks ---------------->Example

Thread Transition States ----------->Example

Thread Thread Priority
A process is a self-contained running computer program. That is, this running program has: its own program counter, its own stack, its own register set, and its own address space. A thread on the other hand is a single flow of control within a process. A process can have multiple concurrently executing threads. Consider a program that consists of three activities: This program can be organized as a single threaded process, the manner that we have been writing programs; or, it can be organized as a triple threaded process. If the program is written as a triple threaded process, each activity can be regarded as a single flow of control. That is: The example above demonstrates that multiple threads can be used to run different parts of a program simultaneously or concurrently. If a computer does not have multiply processors then the threads do not run simultaneously, but rather they run concurrently. For instance, the Java garbage collection thread runs in the background. On a single processor, whenever the program is waiting on something, Java might call the garbage collector to free up space. In this context the threads are running concurrently, otherwise, if they run at the same time then they are running simultaneously.

The concept of thread is not new. Many operating systems and programming languages support the concept. The difference is that:

Go back to the top

Creating Thread

A thread in Java is an object of the Thread class. Implementing threads is achieved in one of tewo ways, namely:

Go back to the top

Implementing the Runnable Interface

The interface has the following specification:

          public interface Runnable
          {
               public void run();
          }
The single run() method implemented, defines an independent path of execution. That is, it provides the entry point and the exit point for the thread. This means tha the thread ends when the run() method ends.

The procedure for creating threads based on the runnable interface is as follows:

  1. Create a class that implements the Runnable interface, by supplying the code for the run() method. The run() method will be executed by the thread
  2. Create an object of the thread class. Pass to the constructor of the thread class an object of the class implementing the Runnable interface.
  3. Invoke the start() method found in the Thread class.
Go back to the top

Extending the Thread class

A class can extend the Thread class. Various constructors exists for the Thread class in the java.lang package. Four of them are as follows: The name of a thread can be retrieve by using the method getName() method.

A class can extend the Thread class to create a thread. The typical procedure is as follows:

  1. A class extending the Thread class overrides the run() method definedin the Thread class.
  2. This subclass may call a Thread constructor explicitly in its constructors to initialize the thread.
  3. The start()method inherited from the Thread class is invoked to make this thread eligible for running.
Go back to the top

Thread Synchronization

Threads share the same resources. For instance, they share the same memory space. There are critical situations where it is desirable that only one thread at a time has access to the shared resource. For instance, if a thread that is reading from a disk should be allowed to complete its reading operation before another thread attemps to access the same resource. In everyday experiences, it would be highly undesirable for two people to be accessing a joint account simultaneously. But rather, we would prefer the one to finish the transaction before the other person gets hold of the account. Java provides high-level concepts for synchronizing shared resources.

Go back to the top

Monitor

Java uses the concept of a monitor to synchronize access to a shared resource. A monitor can be likened to a region of code, representing a shared resource. Threads gain access to a shared resource by first acquiring the monitor associated with the resource. At any given time, no more than one thread can own the monitor, and thereby have access to the shred resource. A monitor enforces the following rules:
  1. No other thread can enter a monitor if another thread has already acquire the monitor. Threads wishing to acquire the monitor must wait for the monitor to become available.
  2. When a thread exits a monitor, a waiting thread is given the monitor.
Ther are two way in which code can be synchronized, namely: Synchronized Methods and Synchronized Blocks.

Synchronized Methods

If the method of an object should be only be executed by one thread at a time, then the method must be modified with the keyword synchronized. A thread wishing to execute a synchronized method must first get ownership of the monitor. If the monitor is already owned by another thread, the calling thread waits. The general format for specifying a synchronized method is as follows:

     class Bank
     {
        Bank(){}

        synchronized void upDate(String 
str)
        {
             System.out.print("[" + str);
             try
             {
	              Thread.sleep(1000);
             }
             catch(InterruptedException e)
             {

             }
             System.out.println("]");
        }
    }

 

Synchronized Blocks

Thet modifier synchronized allows one to fine-grained the synchronization process on an object. That is, you can synchronize a local portion of a piece of code. For instance, instead of synchronizing the mther upDate(), we could simple synchronize the variable account.

     public void run()
     {
          synchronized(account)
          {
	         account.upDate(str);
          }
     }
If this appraoch is to be used you must observe the construct. It is as follows:

        synchronized (objectReference) { 
sourceCode  } 

Go back to the top

Thread Transition States

Threads can exist in different states. By just calling the thread's start method does not gaurantee that the thread will gain access to the CPU and state to run right away. The following are the possible states in which a thread may find itself:

Runnable State

When a thread calls the start method, the thread first enters the Runnable State. In this state, the thread is said to be eligilbe to be run, sometime called the Ready-To-Run state. From here the scheduler (of the operating system) decides which thread gets to run. The thread that is selected to run leaves the Ready-To-Run state and it enters the Running state. Meaning that the operating system grants it the use of the CPU. A running thread may elect to:

  1. Relinguish its possession of the CPU and return to the Ready-To-Run, or
  2. If it finishes its operation or is terminated for whatever reason, it is thrown in the Dead state, or
  3. It may remove it self and be placed in the Non-Runnable state.
If it chooses the first option then calls the static method yield() in the Thread class. The thread is now placed back in the Ready-To-Run state and it is now at the mercy of the scheduler as to when it will run again. If there are no threads waiting in the Ready-To-Run state, this thread continues to run. If there are other threads in the Ready-To-Run state, then their priorities determine which thread gets to execute.

Dead State

If it chooses the second option, the thread cannot be resurrected. A new thread of execution must be explicitly started by calling the start() method.

Non-Runnable States

In the case of the third option, a thread can can be removed from the Runnable state to the non-runnable state. A thread remains in the non-runnable state until a special transition moves it back in the ready-to-run state. The different states within the non-runnable state are:

Go back to the top

Thread Priority

Threads are assigned priority that the thread scheduler can use to determine which thread gets the use of the CPU. The scheduler usually decides to let the thread with the highest priority in the ready-to-run state get the CPU. Priorities are integer values in the range from 1 to 10. The lowest priority is given the the constant:

  • Thread.MIN_PRIORITY = 1
  • Thread.NORM_PRIORITY = 5
  • Thread.MAX_PRIORITY = 10

    The default priority is Thread.NORM_PRIORITY = 5. A thread inherits the priority of its parent thread. Priority of a thread can be set using the setPriority() method. The priority of a thread can be retrieved by using the getPriority() method. Both methods are found in the Thread class.

    Go back to the top


    Go Back