Unit 11 : Multithreaded programming

3rd Semester

A multithreaded program contains two or more parts that can run concurrently. Each part of such a program is called a thread, and each thread defines a separate path of execution. Thus, multithreading is a specialized form of multitasking.
 There are two distinct types of multitasking: process-based and thread-based.
 A process-based multitasking is the feature that allows our computer to run two or more programs concurrently. For example, process-based multitasking enables us to run the Java compiler at the same time that we are using a music player.
 In a thread-based multitasking environment, the thread is the smallest unit of dispatchable code. This means that a single program can perform two or more tasks simultaneously.
 Multitasking threads require less overhead than multitasking processes.
 Multithreading enables us to write very efficient programs that make maximum use of the CPU,because idle time can be kept to a minimum

Life Cycle of a Thread


A thread goes through various stages in its life cycle. For example, a thread is born, started, runs, and then dies. Following diagram shows complete life cycle of a thread.

  • New: A new thread begins its life cycle in the new state. It remains in this state until the program starts the thread. It is also referred to as a born thread.
  • Runnable: After a newly born thread is started, the thread becomes runnable. A thread in this state is considered to be executing its task.
  • Waiting: Sometimes a thread transitions to the waiting state while the thread waits for another thread to perform a task. A thread transitions back to the runnable state only when another thread signals the waiting thread to continue executing.
  • Timed waiting: A runnable thread can enter the timed waiting state for a specified interval of time. A thread in this state transitions back to the runnable state when that time interval expires or when the event it is waiting for occurs.
  •  Terminated: A runnable thread enters the terminated state when it completes its task or otherwise terminates.





Thread Priority

 Java assigns to each thread a priority that determines how that thread should be treated with respect to the others.
 Thread priorities are integers that specify the relative priority of one thread to another.
 Java priorities are in the range between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10). By default, every thread is given priority NORM_PRIORITY (a constant of 5).
 Threads with higher priority are more important to a program and should be allocated processor time before ower-priority threads. However, thread priorities cannot guarantee the order in which threads execute and very much platform dependentant.
 A thread’s priority is used to decide when to switch from one running thread to the next. This is called a context switch
The rules that determine when a context switch takes place are simple:
 A thread can voluntarily relinquish control. This is done by explicitly yielding, sleeping, or blocking on pending I/O. In this scenario, all other threads are examined, and the highestpriority thread that is ready to run is given the CPU.
 A thread can be preempted by a higher-priority thread. In this case, a lower-priority thread that does not yield the processor is simply preempted—no matter what it is doing—by a higher-priority thread. Basically, as soon as a higher-priority thread wants to run, it does. This is called preemptive multitasking.

How to create Thread




Java defines two ways in which a thread can be created:
I. We can implement the Runnable interface.
II. We can extend the Thread class, itself.

Creating Thread by Implementing Runnable interface
The easiest way to create a thread is to create a class that implements the Runnable interface.
 To implement Runnable, a class need only implement a single method called run( ), which is declared like this:
public void run( )
We will define the code that constitutes the new thread inside run() method. It is important to understand that run() can call other methods, use other classes, and declare variables, just like the main thread can.
 After we create a class that implements Runnable, you will instantiate an object of type Thread from within that class. Thread defines several constructors. The one that we will use is shown here:
Thread(Runnable threadOb, String threadName);
Here threadOb is an instance of a class that implements the Runnable interface and the name of the new thread is specified by threadName.
 After the new thread is created, it will not start running until you call its start( ) method, which is declared within Thread. The start( ) method is shown here:
void start( );
Here is an example that creates a new thread and starts it running:
Creating thread by implementing Runnable interface.

Output:





Creating Thread by Extending Thread class

The second way to create a thread is to create a new class that extends Thread, and then to create an instance of that class.
The extending class must override the run ( ) method, which is the entry point for the new thread. It must also call start ( ) to begin execution of the new thread.
Creating Thread by Extending Thread class.

Output:

 





How to create Multiple Threads

So far, you have been using only two threads: the main thread and one child thread. However, our
program can spawn as many threads as it needs. For example, the following program creates three
child threads:
Multiple Thread Creation by implementing Runnable interface






Output

As we can see, once started, all three child threads share the CPU. Notice the call to sleep (10000) in main( ). This causes the main thread to sleep for ten seconds and ensures that it will finish last.

Using isAlive( ) and join( )






Two ways exist to determine whether a thread has finished. First, we can call isAlive( ) on the thread.This method is defined by Thread, and its general form is shown here:
final boolean isAlive( )
The isAlive( ) method returns true if the thread upon which it is called is still running. It returns false otherwise.
While isAlive( ) is occasionally useful, the method that you will more commonly use to wait for a thread
to finish is called join( ), shown here:
final void join ( ) throws InterruptedException
This method waits until the thread on which it is called terminates. Its name comes from the concept of the calling thread waiting until the specified thread joins it. Additional forms of join ( ) allow you to specify a maximum amount of time that you want to wait for the specified thread to terminate.
Use of isAlive() and join() methods






Output:
l

Synchronization

When two or more threads need access to a shared resource, they need some way to ensure that the resource will be used by only one thread at a time. The process by which this is achieved is called synchronization.
Key to synchronization is the concept of the monitor (also called a semaphore). A monitor is an object that is used as a mutually exclusive lock, or mutex. Only one thread can own a monitor at a given time. When a thread acquires a lock, it is said to have entered the monitor. All other threads attempting to enter the locked monitor will be suspended until the first thread exits the monitor. These other threads are said to be waiting for the monitor. A thread that owns a monitor can reenter the same monitor if it
so desires.






Using Synchronized Methods:
Synchronization is easy in Java, because all objects have their own implicit monitor associated with them. To enter an object’s monitor, just call a method that has been modified with the synchronized keyword. While a thread is inside a synchronized method, all other threads that try to call it (or any other synchronized method) on the same instance have to wait. To exit the monitor and relinquish control of the object to the next waiting thread, the owner of the monitor simply returns from the synchronized method.Thread Synchronization using synchronized method.

Output:
Output:
[Hello]
[Synchronized]
[World]

Using synchronized Statement:


While creating synchronized methods within classes that you create is an easy and effective means of achieving synchronization, it will not work in all cases. To understand why, consider the following. Imagine that you want to synchronize access to objects of a class that was not designed for multithreaded access. That is, the class does not use synchronized methods. Further, this class was not created by you, but by a third party and you do not have access to the source code. Thus, you can’t add synchronized to the appropriate methods within the class. How can access to an object of this class be synchronized? Fortunately, the solution to this problem is quite easy: You simply put calls to the methods defined by this class inside a synchronized block.






This is the general form of the synchronized statement:
synchronized (object) {
// statements to be synchronized
}
Here, object is a reference to the object being synchronized. A synchronized block ensures that a call to
a method that is a member of object occurs only after the current thread has successfully entered
object’s monitor.
Thread Synchronization using synchronized statement.






Output:
[Hello]
[Synchronized]
[World]

Wait, notify and notifyAll

wait( ) tells the calling thread to give up the monitor and go to sleep until some other thread enters the same monitor and calls notify( ). notify( ) wakes up the first thread that called wait( ) on the same object. notifyAll( ) wakes up all the threads that called wait( ) on the same object. The highest priority thread will run first.
These methods are declared within Object, as shown here:
final void wait( ) throws InterruptedException
final void notify( )
final void notifyAll( )






Short Type Questions
1. Define thread. Differentiate between thread based multi tasking and process based multi tasking.
2. Why thread priorities are set?
3. Define race condition.
4. Define thread synchronization.
5. How a thread is implemented in java?
6. Differentiate between wait () and sleep method.
7. Differentiate between notify () and notifyAll().





Long Type Questions
1. Define thread. Discuss the life cycle of a thread with neat diagram.
2. Discuss the importance of thread priorities.
3. Discuss how synchronization in threads is achieved using synchronized method.
4. Explain how a thread is created by implementing Runnable interface.
5. Explain how a thread is created by extending thread class.
6. Write Short notes on following:
a) isAlive()
b) join()
c) notify()
d) notifyAll()
e) wait()
f) sleep()