Multi Threading
Multi Threading
Introduction to Threads
Computers can perform many tasks concurrently download a file, print a file, receive email, etc. Sequential languages such as C and C++ do not allow the specification of concurrent processes. Java, on the other hand offers primitives for turning a program into separate, independentlyrunning subtasks. Each of these independent subtasks is called a thread You program as if each thread runs by itself and has the CPU to itself.
Whats a Thread?
A process is an executing program
o o memory allocated by OS usually no memory sharing between processes
A thread is a single sequential flow of control o runs in the address space of a process o has its own program counter and its own stack frame A thread is a path of execution through a program. Single threaded programs->one path of execution Multiple threaded programs -> two or more Threads run in methods or constructors. The threads go into the methods and follow their instructions.
Overview of Multitasking
Each of programs has at least one thread within it. Single thread in a single process Process begins execution at a well-known point. (i.e main () ) Execution of statements follow a predefined order. During execution process has access to certain data: threads stack->local variables object references->instance variables class or object references-> static variables
Overview of Multithreading
Analogy : thread process multiple processes within an OS Multiple thread running within a single instance of JVM
In fact, one of the most immediately compelling reasons for multithreading is to produce a responsive user interface.
// Controlling the main Thread. classCurrentThreadDemo { public static void main(String args[]) { Thread t = Thread.currentThread(); System.out.println("Current thread: " + t); // change the name of the thread t.setName("My Thread"); System.out.println("After name change: " + t); try { for (int n = 5; n > 0; n--) { System.out.println(n); System.out.println(t.getName()+" Sleeping"); Thread.sleep(10000); } }catch (InterruptedException e) { System.out.println("Main thread interrupted"); } } }
Creating a Thread
1. One can implement threads in two ways: a. First, by subclassing the Thread class b. Second, by implementing the Runnable interface 2. The Runnable interface allows you to add threading to a class which cannot conveniently extend Thread. 3. A class that implements the Runnable interface (including the Thread class itself) must implement the run() method containing the "body" of the thread. a. public abstract void run()
A thread is a separate thread of execution. In other words, a separate call stack. A Thread is a Java class that represents a thread.
A Thread object represents a thread of execution; youll create an instance of class Thread each time you want to start up a new thread of execution. Each Thread have its own stack of excution
//creating an oddThread to print odd numbers public class OddThread extends Thread { //overriding run method of Thread Class public void run() { System.out.println("Printing odd numbers from 1 to 10"); for (int i = 1; i < 10; i++) { if (i % 2 != 0) { //logic for odd number System.out.println(Thread.currentThread().getName()+ ":" + i); } } } public static void main(String args[]) { //creating an instance o Thread OddThread oddTh = new OddThread(); oddTh.setName("OddThread"); //setting the name of thread oddTh.start(); //starting the thread
} }
OUTPUT: Printing odd numbers from 1 to 10 OddThread:1 OddThread:3 OddThread:5 OddThread:7 OddThread:9
Implemting Runnable
Java does not support multiple inheritance, instead use interfaces Multithreading for an already derived class Implement interface Runnable (java.lang) New class objects "are" Runnable objects Override run method Controls thread, just as deriving from Thread class In fact, class Thread implements interface Runnable Create new threads using Thread constructors Thread( runnableObject ) Thread( runnableObject, threadName )
In this case, you implement the Runnable interface and override its run() method. You pass a reference to an instance of that Runnable implementation to a thread instance and the thread calls back to the run() method in the Runnable object. The thread dies as in the previous method when the process returns from run().
Runnable is in the java.lang package,so you dont need to import it.
class MyRunnable implements Runnable { public void run() to implement.public void run()(with no { arguments).this is where we put the job for(int i =1; i < 6; i++) { wherethe thread is supposed to run.This is System.out.println("Runnable running"); System.out.println(Thread.currentThread.getName()+ I ); the method that goes at bottom of the new stack } } } public class TestThreads { public static void main (String [] args) { Runnable threadJob = new MyRunnable(); Thread myThread = new Thread(threadJob);
Runnable interface has only one method
myThread.start(); System.out.println(\n Back in main method); } } You wont get a new thread of execution until youcall start() on the Thread instance. A thread isnot really a thread until you start it. Before that, its just a Thread instance, like any other object,but it wont have any real threadness.
Pass the new Runnable instance(threadJob) into the newThread constructor. This tells the thread to execute the run() method present in the MyRunnable class.
myThread.start() main()
main Thread
run()
myThread
new
t.start()
Runnabl e
Running
new t.start(); When you start the thread, it moves into the runnable state. This means the thread is ready to run and just waiting for its Big Chance to be selected for execution. At this point, there is a new call stack for this thread.
A Thread instance has been created but not started. In other words, there is a Thread object, but no thread of execution. NEW RUNNABLE
This is the state all threads lust after! To be The Chosen One. The Currently Running Thread. Only the JVM thread scheduler can make that decision. You can sometimes influence that decision, but you cannot force a thread to move from runnable to running. In the running state, a thread (and ONLY this thread) has an active call stack, and the method on the top of the stack is executing.
Run()
evenTh_1
Run()
evenTh_2
public class MultipleEvenThread implements Runnable { //overriding run method of of Runnable interface public void run() { int even = 0; for (int i = 1; i < 10; i++) { if (i % 2 == 0) { //logic for even number even = i; System.out.println(Thread.currentThread().getName() + even); try { Thread.sleep(100); } catch (InterruptedException ie) { System.out.println("Thread has been interrupted"); } } } } }
public class EvenThreadTest { public static void main(String argsp[]) { MultipleEvenThread mulEvnRun = new MultipleEvenThread(); //create the Thread instance and pass the MultipleEvenThread instance Thread evenTh_1 = new Thread( mulEvnRun ); evenTh_1.setName("Even Thread_1"); //seting the thread name evenTh_1.start(); //starting the thread //create another Thread instance and pass the MultipleEvenThread instance Thread evenTh_2 = new Thread( mulEvnRun ); evenTh_2.setName("Even Thread_2"); //seting the thread name evenTh_2.start(); //starting the thread } }
OUTPUT Even Thread_1: Even Thread_2: Even Thread_1: Even Thread_2: Even Thread_1: Even Thread_2: Even Thread_1: Even Thread_2:
2 2 4 4 6 6 8 8
join( )
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:
// This is the entry point for thread. public void run() { try { for (int i = 5; i > 0; i--) { Thread.sleep(1000);
// wait for threads to finish try { System.out.println("Waiting for threads to finish."); th1.join(); th2.join(); } catch (InterruptedException e) { System.out.println("Main thread Interrupted"); } System.out.println("Thread One is alive: " + th1.isAlive()); System.out.println("Thread Two is alive: " + th2.isAlive()); System.out.println("Main thread completes its execution and dies"); } }
OUTPUT Thread One is alive: true Thread Two is alive: true Waiting for threads to finish. One: 5 Two: 5 One: 4 Two: 4 One: 3 Two: 3 One: 2 Two: 2 One: 1 One finsishes its execution and dies Two: 1 Two finsishes its execution and dies Thread One is alive: false Thread Two is alive: false Main thread completes its execution and dies Thread Two is alive: false Main thread completes its execution and dies
4. Timeslicing
a. Each thread gets a quantum of processor time to execute b. After time is up, processor given to next thread of equal priority c. Without timeslicing,each thread of equal priority runs to completion
Thread Execution On win32 Threads are timesliced a. Thread given quantum of time to execute b. Processor then switches to any threads of equal priority 1. Preemption occurs with higher and equal priority threads Setting a Thread's Priority A thread gets a default priority that is the priority of the thread of execution that creates it. For example, in the code //ThreadPriority.java public class ThreadPriority extends Thread { // Demonstrate thread priorities. int chance = 0; private volatile boolean running = true; public void run() { while (running) { chance++; } } public void stopThread() { running = false; } } //ThreadPriorityTest.java public class ThreadPriorityTest { public static void main(String arga[]) { ThreadPriority low = new ThreadPriority(); ThreadPriority high = new ThreadPriority(); low.setPriority( 1 ); high.setPriority( 10 ); low.start(); high.start(); //putting the current Thread i.e main Thread to sleep // will allow only high and low thread to execute try { Thread.sleep(100); } catch (InterruptedException e) { System.out.println("Main thread interrupted."); } low.stopThread(); high.stopThread(); System.out.println("loww-priority thread: " + low.chance); System.out.println("low-priority thread: " + high.chance); } } OUTPUT low-priority thread: 1656585246 high-priority thread: 1630839013
Multithreading Issues
Sharing resources:
A single-threaded program may be thought of as one lonely entity moving around through the problem space and doing one thing at a time. With multithreading two or more threads may coexist and possibly try to use the same resource simultaneously. Colliding over a resource must be prevented or else two threads may try to access the same resource at the same time with undesirable results (e.g. print to the same printer, or adjust the same value, etc.)
The first thread that accesses a resource locks it and then the other threads cannot it, access that resource until it is unlocked.
The logic in our code example is as follows: 1. The Runnable object holds a reference to a single account. 2. Two threads are started, representing Lucy and Fred, and each thread is given a reference to the same Runnable (which holds a reference to the actual account) 3. The initial balance on the account is 5000, and each withdrawal is exactly 5000. 4. In the run() method, we n Make a withdrawal (if there's enough in the account). n Print a statement if the account is overdrawn (which it should never be,since we check the balance before making a withdrawal). 5. The makeWithdrawal() method in the test class (representing the behavior of Fred or Lucy) will do the following: n Check the balance to see if there's enough for the withdrawal. n If there is enough, print out the name of the one making the withdrawal. n Go to sleep for 500 millisecondsjust long enough to give the other partner a chance to get in before you actually make the withdrawal.
withdrawal and print that fact. there wasn't enough in the first place, print a statement showing who you are and the fact that there wasn't enough.
n If
private int balance = 50; public int getBalance() { return balance; } public void withdraw(int amount) { balance = balance - amount; } public void makeWithdrawal(int amt) { if (getBalance() >= amt) { System.out.println(Thread.currentThread().getName() + " is going to withdraw = " + amt); try { Thread.sleep(500); } catch (InterruptedException ex) { } withdraw(amt); System.out.println(Thread.currentThread().getName() + " completes the withdrawal = " + amt); } else { System.out.println("Not enough in account for " + Thread.currentThread().getName() + " to withdraw " + getBalance()); } } } public class Bank implements Runnable { Account acct = new Account(); public void run() { synchronized (acct) { acct.makeWithdrawal(50); if (acct.getBalance() < 0) { System.out.println("account is overdrawn!"); } } } } public class AccountTest { public static void main(String[] args) { Bank r = new Bank(); Thread one = new Thread(r); Thread two = new Thread(r); one.setName("Rizwana"); two.setName("Vaishali"); one.start();
two.start(); } } Rizwana is going to withdraw = 50 Rizwana completes the withdrawal = 50 Not enough in account for Vaishali to withdraw 0 Example for Synchronized method public synchronized void makeWithdrawal(int amt) { if (getBalance() >= amt) { System.out.println(Thread.currentThread().getName() + " is going to withdraw = " + amt); try { Thread.sleep(500); } catch (InterruptedException ex) { } withdraw(amt); System.out.println(Thread.currentThread().getName() + " completes the withdrawal = " + amt); } else { System.out.println("Not enough in account for " + Thread.currentThread().getName() + " to withdraw " + getBalance()); } } }
InterThread Communication
Synchronization is implemented by Monitors An object that can block threads and notify them when it is available is called a monitor. A monitor is associated with an instance of the class; it has a lock and a queue. If a class has one or more synchronized methods, each object (instance) of the class has a monitor. The queue holds all threads waiting to execute a synchronized method. A thread enters the queue by calling wait() inside the method or when another thread is already executing the method. When a synchronized method returns, or when a method calls wait(), another thread may access the object. The scheduler chooses the highest-priority thread among those in the queue. If a thread is put into the queue by calling wait(), it can't be scheduled for execution until some other thread calls notify().
wait() is called by the thread owning the lock associated with a particular object; wait() releases this lock (atomically, i.e., safely)
void notify() void notifyAll() These methods must be called from a synchronized method. These methods notify a waiting thread or threads. notify() notifies the thread associated with the given synchronization object that has been waiting the longest time notifyAll() notifies all threads associated with the given object and is therefore safer than notify() One can mark a variable as "threadsafe" to inform the compiler that only one thread will be modifying this variable // SharedAccess.java // Definition of class SharedAccess that // uses thread synchronization to ensure that both // threads access sharedInt at the proper times. public class SharedAccess { private int sharedInt = -1; private boolean producerTurn = true; // condition variable
public synchronized void setSharedInt(int val) { while (producerTurn == false) { // not the producer's turn try { wait();//wait till consumer consumes the value } catch (InterruptedException e) { e.printStackTrace(); } } sharedInt = val; writeable = false; // consumer turn to consume the value notify(); // tell a waiting thread (consumer thread)to become ready for consuming the value as producer has produced the value } public synchronized int getSharedInt() { while (producerTurn == true) { // not the consumer's turn try { wait(); //wait till producer produces the value } catch (InterruptedException e) { e.printStackTrace(); } } writeable = true; //producer turn to produce a value notify(); // tell a waiting thread(producer) to become ready for producing a new value as consumer has consumed the previous value return sharedInt; } }
// ProduceInteger.java // Definition of threaded class ProduceInteger public class ProduceInteger extends Thread { public SharedAccess pHold; public ProduceInteger(SharedAccess h) { super("ProduceInteger"); pHold = h; } public void run() { for (int count = 1; count <= 5; count++) { pHold.setSharedInt(count); System.out.println("Producer" + count); } } } // ConsumeIntege.java // Definition of threaded class ConsumeIntege public class ConsumeInteger extends Thread { public SharedAccess cHold; public ConsumeInteger(SharedAccess h) { super("ConsumeInteger"); cHold = h; } public void run() { int val; do { val = cHold.getSharedInt(); System.out.println("Consumer:" + val); } while (val != 5); } }
// ProducerConsumerTest.java // Show multiple threads modifying shared object. public class ProducerConsumerTest { public static void main( String args[] ) { SharedAccess h =new SharedAccess(); ProduceInteger p = new ProduceInteger( h ); ConsumeInteger c = new ConsumeInteger( h ); p.start(); c.start(); } }
DEAD LOCK
Deadlock occurs when two threads are blocked, with each waiting for the other's lock. Neither can run until the other gives up its lock, so they'll sit there forever.
Pen
ResourceA LOCKED
PAPER
ResourceB LOCKED
T1
T2
T1 obtains the lock on rsourceA and is waitng for resourceB to release the lock T2 obtains the lock on ResourceB and is waiting for resourceA to release the lock
All it takes for deadlock to occur are two objects and two threads
public class AnotherDeadLock { public static void main(String[] args) { final Object resource1 = "paper"; final Object resource2 = "pencil"; // t1 tries to lock resource1 then resource2 Thread t1 = new Thread() { public void run() { // Lock resource 1 synchronized (resource1) { System.out.println("Thread 1: locked resource 1 " + resource1); try { Thread.sleep(50); } catch (InterruptedException e) { } System.out.println("Thread 1 trying to lock resource 2"); synchronized (resource2) { System.out.println("Thread 1: locked resource 2 " + resource2); } } } }; // t2 tries to lock resource2 then resource1 Thread t2 = new Thread() { public void run() { synchronized (resource2) {
System.out.println("Thread 2: locked resource 2 " + System.out.println("Thread resource2); try { Thread.sleep(50); } catch (InterruptedException e) { } System.out.println("Thread 2 trying to lock resource 1" System.out.println("Thread 1"); synchronized (resource1) {
Class ThreadGroup
java.lang.Object java.lang.ThreadGroup
public class ThreadGroup other extends Object:A thread group represents a set of threads. In addition, a thread group can also include ot
thread groups. The thread groups form a tree in which every thread group except the initial thread group has a parent. A thread is allowed to access information about its own thread group, but not to access information about its thread group's parent thread group or any other thread groups. hread
Constructor Summary
ThreadGroup(String name)
Method Summary
int activeCount()
public class ThreadGroupTest { public static void main(String[] args) throws Exception { ThreadGroup groupA = new ThreadGroup("groupA"); ThreadGroup groupB = new ThreadGroup("groupB"); MyThread run = new MyThread(); Thread t1 = new Thread(groupA, run, "Thread_!"); Thread t2 = new Thread(groupA, run, "Thread_2"); Thread t3 = new Thread(groupB, run, "Thread_#"); Thread t4 = new Thread(groupB, run, "Thread_3"); t1.start(); t2.start(); t3.start(); t4.start(); System.out.println("Details of mainThread group"); ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
System.out.println("Grt the current thread group i.e MAIN" + mainGroup); System.out.println("Active Thread Groups in main = " + mainGroup.activeGroupCount()); System.out.println("No of active threads in groupA " + groupA.activeCount()); System.out.println("No of active threads in groupB " + groupB.activeCount());
System.out.println("Details of ThreadGroupA"); groupA.list(); System.out.println("Details of ThreadGroupB"); groupB.list();
System.out.println("Get the name of groupA = " + groupA.getName()); System.out.println("Get the name of groupB = " + groupA.getName()); System.out.println("Parent of ThreadGroup groupA = " + groupA.getParent()); System.out.println("Parent of ThreadGroup groupB = " + groupB.getParent());
System.out.println("Wait for the threads of groupA to finsih"); t1.join(); t2.join(); System.out.println("Deatroying thread groupA"); groupA.destroy(); System.out.println("IS groupA destroyed " + groupA.isDestroyed()); System.out.println("Wait for the threads of groupB to finsih"); t3.join(); t4.join();
executing in run method executing in run method executing in run method executing in run method
Details of main thread group Grt the current thread group i.e MAINjava.lang.ThreadGroup[name=main,maxpri=10] Active Thread Groups in main = 2 Number of active threads in groupA 2 Number of active threads in groupA 2 Details of ThreadGroupA java.lang.ThreadGroup[name=groupA,maxpri=10] Thread[Thread_1 , 5, groupA] Thread[Thread_2 , 5, groupA] Details of ThreadGroupB java.lang.ThreadGroup[name=groupB,maxpri=10] Thread[Thread_3 , 5 , groupB] Thread[Thread_4 , 5 , groupB] Get the name of groupA = groupA Get the name of groupB = groupA Parent of ThreadGroup groupA = java.lang.ThreadGroup[name=main, maxpri=10] Parent of ThreadGroup groupB = java.lang.ThreadGroup[name=main, maxpri=10] Wait for the threads of groupA to finsih Deatroying thread groupA IS groupA destroyed true Wait for the threads of groupA to finsih Deatroying thread groupB IS groupA destroyed true
Daemon Threads
Any Java thread can be a daemon thread. Daemon threads are service providers for other threads running in the same process as the daemon thread. 1. 2. 3. 4. A daemon thread is a background thread. It is subordinate to the thread that creates it. When the thread that created the daemon thread ends, the daemon thread dies with it When the only remaining threads in a process are daemon threads, the interpreter exits
Thread States
Sleeping/ Waitng/blocked
New This is the state the thread is in after the Thread instance has been created, but the start() method has not been invoked on the thread. It is a live Thread object, but not yet a thread of execution. At this point, the thread is considered not alive. I Runnable This is the state a thread is in when it's eligible to run, but the scheduler has not selected
it to be the running thread. A thread first enters the runnable state when the start() method is invoked, but a thread can also return to the runnable state after either running or coming back from a blocked, waiting, or sleeping state. When the thread is in the runnable state, it is considered alive. Running This is it. The "big time." Where the action is. This is the state a thread is in when the thread scheduler selects it (from the runnable pool) to be the currently executing process. A thread can transition out of a running state for several reasons,
Waiting/blocked/sleeping This is the state a thread is in when it's eligible to run. all have one thing in common: the thread is still alive, but is currently not eligible to run. In other words, it is not runnable, but it might return to a runnable state later if a particular event occurs blocked A thread may be blocked waiting for a resource (like I/ or an object's lock), in which case the O event that sends it back to runnable is the availability of the resource sleeping: A thread may be sleeping because the thread's run code tells it to sleep for some period of time, in which case the event that sends it back to runnable is that it wakes up because its sleep time has expired. waiting, because the thread's run code causes it to wait, in which case the event that sends it back to runnable is that another thread sends a notification that it may no longer be necessary for the thread to wait Dead A thread is considered dead when its run() method completes. It may still be a viable Thread object, but it is no longer a separate thread of execution. Once a thread is dead, it can never be brought back to life
Unrewarded complexity, such as having a separate thread to update each element of an array An additional advantage to threads is that they are light execution context switches