Terminologies Module - 4 Multi-Threaded Programming Process: A program under execution is called as process. Thread: A smallest component of a process that can be executed independently. OR A thread is an independent path of execution within a single program. Multi-Threaded Programming: A process with two or more threads is being executed concurrently. Process based multi-tasking: It allows executing two or more processes concurrently. Example: Browsing the internet, editing PowerPoint presentation concurrently. Thread based multi-tasking: It allows executing two or more threads concurrently. Example: Assume a program will be having 3 methods namely A(), B(), C(). Say thread T1, executes A(), thread T2 executes B(), Thread T3 executes C() concurrently. Difference between Process and Thread Process Program under execution is called as process Each process has unique address space Inter process communication is expensive and limited Processes are heavy weight Thread Component or part of a program that can be executed independently is called as thread Threads shares same address space Inter thread communication is easier and inexpensive Java cannot handle process based multitasking Threads are light weight Java can handle thread based multitasking Thread Priorities: o It is an integer number assigned to threads. o A priority indicates how one thread should be treated over other threads.
o Thread priority is used to decide when to switch from one running thread to other. o A method of switching from one running thread or process to other thread or process respectively is known as context switching. When context switching happens o A thread can voluntarily relinquish control i.e. running thread releases the CPU to run highest priority thread voluntarily or A thread can be preempted by a higher priority thread. Main Thread o When Java program starts execution, one thread begins immediately, that thread is termed as main thread. o Main thread is required for two reasons, namely This thread spawns child threads Performs various shutdown activities before completing execution. o Main thread is a last thread to complete execution. Thread Life Cycle There are five states a thread can possess in its life time, namely 1. New: Thread is in new state, when an instance of thread class is created and before calling start( ) method. 2. Runnable: A thread is in runnable state after invocation of start() method, but the thread scheduler has not selected it to be the running thread. 3. Running: The thread is in running state if the thread scheduler has selected it. 4. Non-Runnable (Blocked): This is the state when the thread is still alive, but is currently not eligible to run. 5. Terminated: A thread is in terminated or dead state when its run() method exits.
Thread Class The Thread class contains following constructors and functions. Constructors Thread( ) Thread(String Name) Thread(Runnable R) Thread(Runnable R, String Name) Functions public void start( ) public void run( ) public void sleep( ) public void sleep(long millisecs) Description Calls run( ) method to begin thread execution Contains code that is to be executed by thread Sends currently executing thread to sleep mode Sends currently executing thread to
public int getpriority( ) public void setpriority(int priority) public String getname( ) public Thread currentthread( ) public int getid( ) public boolean isalive( ) public void join( ) public void join(long ms) How to create Thread in Java? There are two ways to create threads in Java, namely 1. By extending Thread class 2. By implementing Runnable interface Creating Thread By extending Thread class Follow below steps to create thread by extending Thread class, 1. Extend Sub class by Thread class 2. Override run( ) method of Thread class inside sub class 3. Create sub-class object 4. Call start( ) method by sub-class object sleep mode for specified amount of time Returns priority of the Thread Changes priority of current thread Returns name of current thread Returns reference of the currently executing thread Returns ID of the thread Returns true, if thread is alive Returns false, if thread has completed execution Waits for thread to die Waits for thread to die for specified milli seconds Below program demonstrates the creation of thread. /* ThreadDemo.java */ class threxample extends Thread Thread ----"); public void run() public class ThreadDemo System.out.println("---- Execution by Child public static void main(string [] args) threxample t1 = new threxample(); threxample t2 = new threxample();
t1.start(); t2.start(); Output: ---- Execution by Child Thread ---- ---- Execution by Child Thread ---- Below program demonstrates various functions of Thread class. /* ThreadDemo.java */ class threxample extends Thread threxample(string thname) super(thname); public void run() System.out.println("---- New Thread ----"); System.out.println("Current Thread : " +getname()); System.out.println("Thread Priority: " +getpriority()); System.out.println("Thread Status : " +isalive()); System.out.println("Thread Id : " +getid()); public class ThreadDemo public static void main(string [] args) threxample t1 = new threxample("one"); threxample t2 = new threxample("two"); System.out.println("Current Thread : " +Thread.currentThread()); t1.start(); t2.start(); Output: Current Thread : Thread[main,5,main] ---- New Thread ----
Current Thread : TWO Thread Priority: 5 Thread Status : true Thread Id : 9 ---- New Thread ---- Current Thread : ONE Thread Priority: 5 Thread Status : true Thread Id : 8 Creating Thread by Implementing Runnable Interface Follow below steps to create thread by implementing Runnable Interface 1. Create sub class by implementing Runnable interface 2. Override run( ) method inside the subclass 3. Create Thread object by calling Thread constructor and pass object of sub class as parameter for which Thread should be created 4. Call start( ) method by Thread object Below program demonstrates creation of thread by implementing Runnable interface. /* ThreadRunn.java */ public class threadrun implements Runnable public void run() System.out.println("Thread is executing using runnable interface"); public static void main(string[] args) threadrun tr = new threadrun(); Thread t = new Thread(tr); Thread t1 = new Thread(tr); Thread t2 = new Thread(tr); t.start(); t1.start(); t2.start();
Output: Thread is executing using runnable interface Thread is executing using runnable interface Thread is executing using runnable interface How to create multiple threads Below program demonstrates the creation of multiple threads /* thexample.java */ class thexample implements Runnable Thread t; thexample(string thname) t = new Thread(this, thname); System.out.println("New Thread ----" +t.getname() +"---- is created"); t.start(); public void run() System.out.println("Thread --- " +t.getname() +" ---is executing"); public class threadrunmul public static void main(string [] args) Output: new thexample("one"); new thexample("two"); New Thread ----ONE---- is created New Thread ----TWO---- is created Thread --- TWO ---is executing Thread --- ONE ---is executing
isalive( ) and join( ) 1. Function belongs to : Thread class Function Name: isalive( ) Task: Checks whether the thread has finished execution Prototype: final boolean isalive( ) Return value: true, if thread upon which it is called is still running false, if thread upon which it is called is completed execution 2. Function belongs to : Thread class Function Name: join( ) Task: waits until the thread on which it is called terminates Prototype: final void join( ) or final void join(long millisecs) Return value: No return value Below program demonstrates above two functions class thrun implements Runnable Thread t; thrun(string thname) t = new Thread(this, thname); t.start(); public void run() try for(int i = 1; i <= 2; i++) +i); System.out.println("Thread " +t.getname() +" " Thread.sleep(1000); catch(interruptedexception e) System.out.println(t.getName() +" is Interrupted"); System.out.println(t.getName() +" is exiting"); public class thmulrun
public static void main(string [] args) thrun t1 = new thrun("one"); thrun t2 = new thrun("two"); System.out.println("Main Thread Started"); System.out.println("Thread ONE is alive " +t1.t.isalive()); System.out.println("Thread ONE is alive " +t2.t.isalive()); finish"); try System.out.println("Waiting for Child threads to t1.t.join(); t2.t.join(); catch(interruptedexception e) System.out.println("Main thread Interrupted"); System.out.println("Main Thread Completed"); Output: Main Thread Started Thread ONE is alive true Thread ONE is alive true Waiting for child threads to finish Thread TWO 1 Thread ONE 1 Thread TWO 2 Thread ONE 2 TWO is exiting ONE is exiting Main Thread Completed
Thread Priorities Thread priorities are used by scheduler to decide when each thread should be allowed to run. Functions Associated with Thread Priorities 1. Function belongs to : Thread class Function Name: setpriority( ) Task: Changes priority of current thread Prototype: public void setpriority( ) Return value: No return value 2. Function belongs to : Thread class Function Name: getname( ) Task: Fetches the name of current thread on which it is called Prototype: public String getname( ) Return value: Returns name of the thread 3. Function belongs to : Thread class Function Name: setname( ) Task: Sets name to thread on which it is called Prototype: public void setname(string Name) Return value: No return value 4. Function belongs to : Thread class Function Name: getid( ) Task: Fetches the Id of thread on which it is called Prototype: public int getid( ) Return value: Returns integer number Below program demonstrates various functions of Thread class. /* ThreadDemo.java */ class threxample extends Thread threxample(string thname) super(thname); public void run() System.out.println("---- New Thread ----"); System.out.println("Current Thread : " +getname());
System.out.println("Thread Priority: " +getpriority()); System.out.println("Thread Status : " +isalive()); System.out.println("Thread Id public class ThreadDemo public static void main(string [] args) threxample t1 = new threxample("one"); threxample t2 = new threxample("two"); System.out.println("Current Thread : " +Thread.currentThread()); Output: t1.start(); t2.start(); Current Thread : Thread[main,5,main] ---- New Thread ---- Current Thread : TWO Thread Priority: 5 Thread Status : true Thread Id : 9 ---- New Thread ---- Current Thread : ONE Thread Priority: 5 Thread Status : true Thread Id : 8 : " +getid());
Synchronization When two or more threads needs to access shared data, then data inconsistency problem arises. Imagine a scenario, o Thread T1 is writing data into a file numbers.txt. o Thread T2 is reading data from a file numbers.txt. In this scenario, when T1 is writing, if T2 reads the file concurrently, data may not be correct. Hence, when one thread is using shared resource, other threads should not be allowed to use until first thread completes the task. In Java, synchronization is achieved using monitor or lock. Each object has unique lock associated with them. A thread that needs to access shared resource, first acquires the lock, as soon as completes the execution, thread automatically releases the lock. To synchronize the function, prefix the keyword synchronized in function definition Example: In the below program, thread executes the function disp( ), program without synchronization. Synchronized Methods /* ThreadSyncOne.java (Without Synchronization)*/ class First void disp() System.out.println("Good"); try Thread.sleep(500); catch (InterruptedException ex) System.out.println("Thread Interrupted"); System.out.println("Morning"); class Two extends Thread First f = new First(); Two(First f1) f = f1; public void run() f.disp();
public class ThreadSyncOne public static void main(string [] args) First f = new First(); Two t1 = new Two(f); Two t2 = new Two(f); t1.start(); t2.start(); Output: Good Good Morning Morning Above Program using synchronized keyword /* ThreadSyncOne.java (Using Synchronization)*/ class First void disp() System.out.println("Good"); try Thread.sleep(500); catch (InterruptedException ex) System.out.println("Thread Interrupted"); System.out.println("Morning"); class Two extends Thread First f = new First(); Two(First f1) f = f1; public void run() f.disp();
public class ThreadSyncOne public static void main(string [] args) First f = new First(); Two t1 = new Two(f); Two t2 = new Two(f); t1.start(); t2.start(); Output: Good Morning Good Morning Synchronized Blocks Synchronized blocks are required when, o Synchronize access to objects of a class that was not designed for multithreading. o Class does not use synchronized methods. During above conditions, synchronized blocks can be used. synchronized(object) //Statements to be synchronized Where, Object is a reference to the object being referenced. Below, program demonstrates the use of synchronized block. /* ThreadSyncBlock.java*/ class Callme void disp() System.out.println("Good"); try Thread.sleep(500); catch (InterruptedException ex) System.out.println("Thread Interrupted"); System.out.println("Morning"); class Caller implements Runnable Callme c; Thread t;
Output: Good Morning Good Morning public Caller(Callme throbj) c = throbj; t = new Thread(this); t.start(); public void run() synchronized(c) c.disp(); public class ThreadSyncBlock public static void main(string [] args) Callme cmobj = new Callme(); Caller c1 = new Caller(cmObj); Caller c2 = new Caller(cmObj); Inter Thread Communication wait( ) It is mechanism that allows two or more synchronized threads to communicate with each other. In Java, Inter thread communication is achieved using o wait( ) o notify( ) o notifyall( ) The wait method releases the lock of current thread and moves it to waiting state. Thread will awake, when other thread calls notify( ) or notifyall( ) method for the object, or till specified time elapses. Prototype: 1. public final void wait( ) throws InterruptedException 2. public final void wait(long timeout) throws InterruptedException
notify( ) Notifies the thread in waiting state on the same object to wake up. Prototype: notifyall( ) 1. public final void notify( ) Notifies all threads in waiting state on the same object to wake up. Prototype: 1. public final void notifyall( ) Process of Inter Thread Communication Working of Threads with respect to above diagram 1. Threads enter to acquire lock. 2. Lock is acquired by on thread. 3. Now thread goes to waiting state if you call wait() method on the object. Otherwise it releases the lock and exits. 4. If you call notify() or notifyall() method, thread moves to the notified state (runnable state). 5. Now thread is available to acquire lock. 6. After completion of the task, thread releases the lock and exits the monitor state of the object.
Difference between wait( ) and sleep( ) wait( ) method releases the lock wait( ) sleep( ) Method of object class Non-static method Should be notified by notify( ) or notifyall( ) sleep( ) method does not releases the lock Method of Thread class Static method wakes up after specified time Below program demonstrates the withdrawal and depositing money using inter thread communication. Scenario: Available balance in the account is 5000. Say, Thread T1, tries to withdraw an amount of 10000. Since, balance is less, thread cannot withdraw. It calls wait( ) and goes to waiting state until another thread deposits money and wakes up this thread. Say, Thread T2, deposits 10000, now balance is 15000. Now, T2 calls notify( ) method and wakes up thread T1. Now, T1 resumes with its execution. /* threadwaitnotify */ class Customer int amount = 5000; synchronized void withdraw(int withamount) System.out.println("About to withdraw"); if(amount < withamount) System.out.println("No Sufficient Funds"); try wait(); catch(exception e) System.out.println("Waiting to deposit, but done"); amount = amount - withamount; System.out.println("Withdrawl of " +withamount +" completed"); synchronized void deposit(int depamount)
System.out.println("Depositing Amount"); amount = amount + depamount; System.out.println("Depositing " +depamount); notify(); public class ThreadWaitNotify public static void main(string [] args) final Customer c = new Customer(); new Thread() public void run() c.withdraw(10000);.start(); new Thread() public void run() c.deposit(10000);.start(); Producer Consumer Problem Problem In computing, the producer consumer problem (also known as the boundedbuffer problem) is a classic example of a multi-process synchronization problem. The problem describes two processes, the producer and the consumer, which share a common, fixed-size buffer used as a queue. The producer s job is to generate data, put it into the buffer, and start again. At the same time, the consumer is consuming the data (i.e. removing it from the buffer), one piece at a time. To make sure that the producer won t try to add data into the buffer if it s full and that the consumer won t try to remove data from an empty buffer. Solution The producer is to either go to sleep or discard data if the buffer is full. The next time the consumer removes an item from the buffer, it notifies the producer, who starts to fill the buffer again. In the same way, the consumer can go to sleep if it finds the buffer to be empty. The next time the producer puts data into the buffer, it wakes up the sleeping consumer.
An inadequate solution could result in a deadlock where both processes are waiting to be awakened. Below program demonstrates the Producer Consumer problem using Linked List. /* ThreadExample */ import java.util.linkedlist; public class Threadexample public static void main(string[] args) throws InterruptedException // Object of a class that has both produce() // and consume() methods final PC pc = new PC(); // Create producer thread Thread t1 = new Thread(new Runnable() @Override public void run() try pc.produce(); catch(interruptedexception e) e.printstacktrace(); ); // Create consumer thread Thread t2 = new Thread(new Runnable() @Override public void run() try pc.consume(); catch(interruptedexception e) e.printstacktrace(); );
// Start both threads t1.start(); t2.start(); // t1 finishes before t2 t1.join(); t2.join(); // This class has a list, producer (adds items to list // and consumber (removes items). public static class PC // Create a list shared by producer and consumer // Size of list is 2. LinkedList<Integer> list = new LinkedList<>(); int capacity = 2; // Function called by producer thread public void produce() throws InterruptedException int value = 0; while (true) synchronized (this) // producer thread waits while list // is full while (list.size()==capacity) wait(); System.out.println("Producer produced-" + value); // to insert the jobs in the list list.add(value++); // notifies the consumer thread that // now it can start consuming notify(); // makes the working of program easier // to understand Thread.sleep(1000);
// Function called by consumer thread public void consume() throws InterruptedException while (true) synchronized (this) // consumer thread waits while list // is empty while (list.size()==0) wait(); Output: Producer produced-0 Producer produced-1 Consumer consumed-0 Consumer consumed-1 Producer produced-2 Consumer consumed-2 //to retrive the ifrst job in the list int val = list.removefirst(); System.out.println("Consumer consumed-" + val); // Wake up producer thread notify(); // and sleep Thread.sleep(1000);