Introduction

Processes and Threads

In concurrent programming, there are two basic units of execution: processes and threads. In the Java programming language, concurrent programming is mostly concerned with threads. However, processes are also important. A computer system normally has many active processes and threads. This is true even in systems that only have a single execution core, and thus only have one thread actually executing at any given moment. Processing time for a single core is shared among processes and threads through an OS feature called time slicing. It's becoming more and more common for computer systems to have multiple processors or processors with multiple execution cores. This greatly enhances a system's capacity for concurrent execution of processes and threads but concurrency is possible even on simple systems, without multiple processors or execution cores.

Processes

A process has a self-contained execution environment. A process generally has a complete, private set of basic run-time resources; in particular, each process has its own memory space. Processes are often seen as synonymous with programs or applications. However, what the user sees as a single application may, in fact, be a set of cooperating processes. To facilitate communication between processes, most operating systems support Inter-Process Communication (IPC) resources, such as pipes and sockets. IPC is used not just for communication between processes on the same system, but processes on different systems.

Threads

Threads are sometimes called lightweight processes. Both processes and threads provide an execution environment, but creating a new thread requires fewer resources than creating a new process. Threads exist within a process — every process has at least one. Threads share the process's resources, including memory and open files. This makes for efficient, but potentially problematic, communication. Multithreaded execution is an essential feature of the Java platform. Every application has at least one thread — or several if you count "system" threads that do things like memory management and signal handling. But from the application programmer's point of view, you start with just one thread, called the main thread. This thread has the ability to create additional threads

Multitasking: Executing several tasks simultaneously is the concept of multitasking. There are two types of multitasking.

Process-based multitasking. Thread based multitasking.

Process-based multitasking

Executing several tasks simultaneously where each task is a separate independent process such type of multitasking is called process-based multitasking. Example: While typing a java program in the editor we can able to listen to mp3 audio songs at the same time we can download a file from the net all these tasks are independent of each other and executing simultaneously and hence it is Process-based multitasking. This type of multitasking is best suitable at "os level".

Thread based multitasking

Executing several tasks simultaneously where each task is a separate independent part of the same program, is called Thread based multitasking. And each independent part is called a "Thread". 

1) This type of multitasking is best suitable for "programmatic level".

 2) When compared with "C++", developing multithreading examples is very easy in java because java provides inbuilt support for multithreading through a rich API (Thread, Runnable, ThreadGroup, ThreadLocal...etc). 

3) In multithreading on 10% of the work, the programmer is required to do and 90% of the work will be down by java API. 4) The main important application areas of multithreading are:

  • To implement multimedia graphics.
  • To develop animations.
  • To develop video games etc.
  • To develop web and application servers

5) Whether it is process-based or Thread based the main objective of multitasking is to improve the performance of the system by reducing response time.

The ways to define instantiate and start a New Thread

1) Defining a Thread by extending "Thread class"

The Thread class itself implements Runnable, though its run method does nothing. An application can subclass Thread, providing its own implementation of run, as in the HelloThread example:

public class HelloThread extends Thread {
public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new HelloThread()).start(); } } . .

The Thread class defines a number of methods useful for thread management. These include static methods, which provide information about or affect the status of, the thread invoking the method. The other methods are invoked from other threads involved in managing the thread and Thread object.

2) Implement a Runnable interface. The Runnable interface defines a single method, run, meant to contain the code executed in the thread. The Runnable object is passed to the Thread constructor, as in the HelloRunnable example:

public class HelloRunnable implements Runnable {
public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new Thread(new HelloRunnable())).start(); } }

Which of these idioms should you use?

The first idiom, which employs a Runnable object, is more general because the Runnable object can subclass a class other than Thread. The second idiom is easier to use in simple applications but is limited by the fact that your task class must be a descendant of Thread. This lesson focuses on the first approach, which separates the Runnable task from the Thread object that executes the task.

Thread Scheduler

If multiple threads are waiting to execute then which Thread will execute 1st is decided by "Thread Scheduler" which is part of JVM. Which algorithm or behavior followed by Thread Scheduler we can't expect exactly it is the JVM vendor dependent hence in multithreading examples we can't expect exact execution order and exact output.

Difference between t.start() and t.run() methods

In the case of t.start(), a new Thread will be created which is responsible for the execution of the run() method. But in the case of t.run() no new Thread will be created and run() method will be executed just like a normal method by the main Thread.

Importance of Thread class start() method

For every Thread the required mandatory activities like registering the Thread with Thread Scheduler will take care of by Thread class start() method and programmer is responsible just to define the job of the Thread inside the run() method. That is start() method acts as best assistant to the programmer.

start()
{ 1. Register Thread with Thread Scheduler 2. All other mandatory low level activities. 3. Invoke or calling run() method. }

We can conclude that without executing Thread class start() method there is no chance of starting a new thread in java. Due to this start() is considered as heart of multithreading.

Case 1: If we are not overriding run() method

If we are not overriding run() method then Thread class run() method will be executed which has empty implementation and hence we won't get any output.

class MyThread extends Thread
{} class ThreadDemo { public static void main(String[] args) { MyThread t=new MyThread(); t.start(); } }

It is highly recommended to override run() method. Otherwise don't go for a multithreading concept.

Case 2: Overloading of run() method

OutputExample:
class MyThread extends Thread { public void run() { System.out.println("no arg method"); } public void run(int i) { System.out.println("int arg method"); } } class ThreadDemo { public static void main(String[] args) { MyThread t=new MyThread(); t.start(); } } Output: No arg method

We can overload run() method but Thread class start() method always invokes no argument run() method the other overload run() methods we have to call explicitly then only it will be executed just like normal method.

Case 3: overriding of start() method 

If we override start() method then our start() method will be executed just like a normal method call and no new Thread will be started.

class MyThread extends Thread
{ public void start() { System.out.println("start method"); } public void run() { System.out.println("run method"); } } class ThreadDemo { public static void main(String[] args) { MyThread t=new MyThread(); t.start(); System.out.println("main method"); } } Output: start method main method

Entire output produced by only main Thread. Note : It is never recommended to override start() method.





the life cycle of the Thread


  • Once we created a Thread object then the Thread is said to be in new state or born state.
  • Once we call start() method then the Thread will be entered into Ready or Runnable state.
  • If Thread Scheduler allocates CPU then the Thread will be entered into running state.
  • Once run() method completes then the Thread will be entered into the dead state.

Case 5

After starting a Thread we are not allowed to restart the same Thread once again otherwise we will get runtime exception saying "IllegalThreadStateException".

MyThread t=new MyThread();
t.start();//valid t.start();//we will get R.E saying: IllegalThreadStateException

Case study

class MyRunnable implements Runnable
{ public void run() { for(int i=0;i<5 .="" child="" color="#9e9e9e" font="" i="" system.out.println="" thread=""> .
class ThreadDemo
{ public static void main(String[] args) { MyRunnable r=new MyRunnable(); Thread t=new Thread(r);//here r is a Target Runnable t.start(); for(int i=0;i<10 .="" child="" color="#9e9e9e" font="" i="" main="" output:="" system.out.println="" thread=""> .

We can't expect exact output but there are several possible outputs.

MyRunnable r=new MyRunnable();
Thread t1=new Thread(); Thread t2=new Thread(r);

Case 1: t1.start(): A new Thread will be created which is responsible for the execution of Thread class run()method.


main thread main thread main thread main thread main thread

Case 2: t1.run(): No new Thread will be created but Thread class run() method will be executed just like a normal method call.

main thread
main thread main thread main thread main thread . .

Case 3: t2.start(): New Thread will be created which is responsible for the execution of MyRunnable run() method.

main thread
main thread main thread main thread child Thread child Thread child Thread child Thread child Thread . .

Case 4: t2.run(): No new Thread will be created and MyRunnable run() method will be executed just like a normal method call.

child Thread
child Thread child Thread child Thread child Thread main thread main thread main thread main thread main thread . .

Case 5: r.start(): We will get a compile-time error saying start() method is not available in MyRunnable class.

Compile time error
javac ThreadDemo.java ThreadDemo.java:18: cannot find symbol Symbol: method start() Location: class MyRunnable

Case 6: r.run(): No new Thread will be created and MyRunnable class run() method will be executed just like a normal method call.

child Thread
child Thread child Thread child Thread child Thread main thread main thread main thread main thread main thread

Thread class constructors

Thread t=new Thread();
Thread t=new Thread(Runnable r); Thread t=new Thread(String name); Thread t=new Thread(Runnable r,String name); Thread t=new Thread(ThreadGroup g,String name); Thread t=new Thread(ThreadGroup g,Runnable r); Thread t=new Thread(ThreadGroup g,Runnable r,String name); Thread t=new Thread(ThreadGroup g,Runnable r,String name,long stackSize); . .


Getting and setting the name of a Thread 



Output: main method run method

  • Every Thread in java has some name it may be provided explicitly by the programmer or automatically generated by JVM.
  • Thread class defines the following methods to get and set the name of a Thread.

Methods

public final String getName() public final void setName(String name)

class MyThread extends Thread
{} class ThreadDemo { public static void main(String[] args) { System.out.println(Thread.currentThread().getName());//main MyThread t=new MyThread(); System.out.println(t.getName());//Thread-0 Thread.currentThread().setName("Bhaskar Thread"); System.out.println(Thread.currentThread().getName());//Bhaskar Thread } }

We can get current executing Thread object reference by using Thread.currentThread() method.

Thread Priorities

  • Every Thread in java has some priority it may be default priority generated by JVM (or) explicitly provided by the programmer.
  • The valid range of Thread priorities is 1 to 10[but not 0 to 10] where 1 is the least priority and 10 is highest priority.
  • Thread class defines the following constants to represent some standard priorities. Thread. MIN_PRIORITY----------1 Thread. MAX_PRIORITY----------10 Thread. NORM_PRIORITY--------5
  • There are no constants like Thread.LOW_PRIORITY, Thread.HIGH_PRIORITY
  • Thread scheduler uses these priorities while allocating CPU.
  • The Thread which is having highest priority will get chance for 1st execution.
  • If 2 Threads having the same priority then we can't expect exact execution order it depends on Thread scheduler whose behavior is vendor dependent.
  • We can get and set the priority of a Thread by using the following methods. public final int getPriority() public final void setPriority(int newPriority);//the allowed values are 1 to 10
  • The allowed values are 1 to 10 otherwise we will get runtime exception saying "IllegalArgumentException".

Default priority

The default priority only for the main Thread is 5. But for all the remaining Threads the default priority will be inheriting from parent to child. That is whatever the priority parent has by default the same priority will be for the child also.

class MyThread extends Thread
{} class ThreadPriorityDemo { public static void main(String[] args) { System.out.println(Thread.currentThread().getPriority());//5 Thread.currentThread().setPriority(9); MyThread t=new MyThread(); System.out.println(t.getPriority());//9 } }
OutputExample:
class MyThread extends Thread { public void run() { for(int i=0;i<10 args="" child="" i="" main="" mythread="" public="" static="" system.out.println="" t.setpriority="" t="new" thread="" threadprioritydemo="" tring="" void=""> 1 t.start(); for(int i=0;i<10 i="" main="" span="" system.out.println="" thread="">

1) If we are commenting line 1 then both main and child Threads will have the same priority and hence we can't expect exact execution order. 

 2) If we are not commenting line 1 then child Thread has the priority 10 and main Thread has the priority 5 hence child Thread will get chance for execution and after completing child Thread main Thread will get the chance in this the output is:

child thread
child thread child thread child thread child thread child thread child thread child thread child thread child thread main thread main thread main thread main thread main thread main thread main thread main thread main thread main thread

Some operating systems(like WindowsXP) may not provide proper support for Thread priorities. We have to install separate bats provided by the vendor to provide support for priorities.

Methods to Prevent a Thread from Execution

We can prevent(stop) a Thread execution by using the following methods. 

yield()

join()

sleep()

yield()

yield() method causes "to pause current executing Thread for giving the chance of remaining waiting Threads of same priority".

 If all waiting Threads have the low priority or if there is no waiting Threads then the same Thread will be continued its execution. 

If several waiting Threads with the same priority available then we can't expect exact which Thread will get chance for execution. 

The Thread which is yielded when it gets chance once again for execution depends on the mercy of the Thread scheduler. public static native void yield();


OutputExample:
class MyThread extends Thread { public void run() { for(int i=0;i<5 args="" child="" for="" i="0;i<5;i++)" int="" main="" mythread="" output:="" public="" span="" static="" system.out.println="" t.start="" t="new" thread.yield="" thread="" threadyielddemo="" tring="" void="">

In the above program child Thread always calling yield() method and hence main Thread will get the chance more times for execution. Hence the chance of completing the main Thread first is high. 

 Note : Some operating systems may not provide proper support for the yield() method.

 Join(): If a thread wants to wait until completing some other Thread then we should go for join() method. Example: If a Thread t1 executes t2.join() then t1 should go for waiting state until completing t2.

public final void join()throws InterruptedException public final void join(long ms) throws InterruptedException public final void join(long ms, int ns) throws InterruptedException


Every join() method throws InterruptedException, which is checked exception hence compulsory we should handle either by try-catch or by throws keyword. Otherwise we will get compile-time error.

OutputExample:
class MyThread extends Thread { public void run() { for(int i=0;i<5 args="" catch="" e="" i="" interruptedexception="" ita="" main="" mythread="" nterruptedexception="" public="" static="" system.out.println="" t.join="" t.start="" t="new" thread.sleep="" thread="" threadjoindemo="" throws="" tring="" try="" void="">1 for(int i=0;i<5 ama="" i="" span="" system.out.println="" thread="">

1) If we are commenting line 1 then both Threads will be executed simultaneously and we can't expect exact execution order. 

2) If we are not commenting line 1 then main Thread will wait until completing child Thread in this the output is sita Thread 5 times followed by Rama Thread 5 times.

If we are not Waiting of child Thread untill completing main Thread

OutputExample:
class MyThread extends Thread { static Thread mt; public void run() { try { mt.join(); } catch (InterruptedException e){} for(int i=0;i<5 :="" ain="" args="" child="" for="" hild="" i="0;i<5;i++)" int="" interruptedexception="" main="" mt="Thread.currentThread();" mythread="" output="" public="" span="" static="" system.out.println="" t.start="" t="new" thread.sleep="" thread="" threadjoindemo="" throws="" tring="" void="">

Note : If main thread calls join() on child thread object and child thread called join() on main thread object then both threads will wait for each other forever and the program will be hanged(like deadlock if a Thread class join() method on the same thread itself then the program will be hanged.

class ThreadDemo {
public static void main() throws InterruptedException { Thread.currentThread().join(); --------------- -------- main main } }

Sleep() method



If a thread don't want to perform any operation for a particular amount of time then we should go for sleep() method. public static native void sleep(long ms) throws InterruptedException public static void sleep(long ms, int ns)throws InterruptedException

class ThreadJoinDemo
{ public static void main(String[] args)throws InterruptedException { System.out.println("M"); Thread.sleep(3000); System.out.println("E"); Thread.sleep(3000); System.out.println("G"); Thread.sleep(3000); System.out.println("A"); } } Output: M E G A

Interrupting a Thread

How a Thread can interrupt another thread ? If a Thread can interrupt a sleeping or waiting Thread by using interrupt()(break off) method of Thread class. public void interrupt();

class MyThread extends Thread
{ public void run() { try { for(int i=0;i<5 :="" am="" args="" catch="" e="" got="" i="" interrupted="" lazy="" main="" mythread="" nterruptedexception="" public="" static="" system.out.println="" t.interrupt="" t.start="" t="new" thread.sleep="" thread="" threadinterruptdemo="" tring="" void="">1 System.out.println("end of main thread"); } } End of main thread I am lazy Thread: 0 I got interrupted

1) If we are commenting line 1 then main Thread won't interrupt child Thread and hence child Thread will be continued until its completion.

 2) If we are not commenting line 1 then main Thread interrupts child Thread and hence child Thread won't be continued until its completion in this case the output is as given above.

  • Whenever we are calling interrupt() method we may not see the effect immediately, if the target Thread is in sleeping or waiting state it will be interrupted immediately.
  • If the target Thread is not in sleeping or waiting for state then interrupt call will wait until target Thread will enter into a sleeping or waiting state. Once target Thread entered into a sleeping or waiting state it will effect immediately.
  • In its lifetime if the target Thread never entered into a sleeping or waiting for state then there is no impact of interrupt call simply interrupt call will be wasted.
OutputExample:
class MyThread extends Thread { public void run() { for(int i=0;i<5 args="" catch="" e="" end="" entered="" got="" i="" iam="" interrupted="" into="" lazy="" m="" main="" mythread="" nterruptedexception="" of="" public="" sleeping="" span="" stage="" static="" system.out.println="" t.interrupt="" t.start="" t="new" thread.sleep="" thread="" threadinterruptdemo1="" tring="" try="" void="">

1) In the above program interrupt() method call invoked by main Thread will wait until child Thread entered into a sleeping state. 

2) Once child Thread entered into a sleeping state then it will be interrupted immediately.

Comparison between Yield()  Join() Sleep()

 property Yield() Join() Sleep()
 Purpose?  To pause current executing Thread for giving the chance of remaining waiting Threads of the same priority.If a thread wants to wait until completing some other Thread then we should go for join.  If a thread wants to wait until completing some other Thread then we should go for join. If a thread doesn't want to perform any operation for a particular amount of time then we should go for sleep() method. 
 Is it static? yes  no yes
 Is it final?  no  yes no
 Is it overloaded? No  yes yes
 Is it throws InterruptedException? no  yes yes
 Is it a native method?  yes no sleep(long ms) -->native
sleep(long ms,int ns) -->non-native

Synchronization

1) Synchronized is the keyword applicable for methods and blocks but not for classes and variables.

 2)  If a method or block declared as the synchronized then at a time only one Thread is allowed to execute that method or block on the given object. 

 
3) The main advantage of a synchronized keyword is we can resolve data inconsistency problems.

4) But the main disadvantage of synchronized keyword is it increases waiting time of the Thread and effects the performance of the system.


5) Hence if there is no specific requirement then never recommended to use synchronized keyword.
Internally synchronization concept is implemented by using lock concept.

6) Every object in java has a unique lock. Whenever we are using synchronized keyword then only lock concept will come into the picture. 

 
7) If a thread wants to execute any synchronized method on the given object 1st it has to get the lock of that object. 

8) Once a Thread got the lock of that object then it's allowed to execute any synchronized method on that object. If the synchronized method execution completes then automatically Thread releases lock. 

 
9) While a Thread executing any synchronized method the remaining Threads are not allowed execute any synchronized method on that object simultaneously. But remaining Threads are allowed to execute any non-synchronized method simultaneously. [lock concept is implemented based on the object but not based on method].

OutputExample:
class Display { public synchronized void wish(String name) { for(int i=0;i<5 args="" catch="" d.wish="" d1="" d="" dhoni="" display="" e="" extends="" good="" i="" isplay="" main="" morning:="" mythread="" name="" nterruptedexception="" public="" run="" span="" static="" string="" synchronizeddemo="" system.out.print="" system.out.println="" t1.start="" t1="new" t2.start="" t2="new" this.d="d;" this.name="name;" thread.sleep="" thread="" tring="" try="" void="" yuvaraj="">

If we are not declaring wish() method as synchronized then both Threads will be executed simultaneously and we will get irregular output.

Output:
good morning:good morning:yuvaraj good morning:dhoni good morning:yuvaraj good morning:dhoni good morning:yuvaraj good morning:dhoni good morning:yuvaraj good morning:dhoni good morning:yuvaraj dhoni . .

If we declare wish()method as synchronized then the Threads will be executed one by one that is until completing the 1st Thread the 2nd Thread will wait in this case we will get regular output which is nothing but

Output:
good morning:dhoni good morning:dhoni good morning:dhoni good morning:dhoni good morning:dhoni good morning:yuvaraj good morning:yuvaraj good morning:yuvaraj good morning:yuvaraj good morning:yuvaraj . .

Case 1:

Display d1=new Display();
Display d2=new Display(); MyThread t1=new MyThread(d1,"dhoni"); MyThread t2=new MyThread(d2,"yuvaraj"); t1.start(); t2.start();

Even though we declared wish() method as synchronized but we will get irregular output in this case, because both Threads are operating on different objects. 

Conclusion: If multiple threads are operating on multiple objects then there is no impact of Synchronization. If multiple threads are operating on same java objects then the synchronized concept is required(applicable).

Class level lock

  • Every class in Java has a unique lock. If a thread wants to execute a static synchronized method then it required a class level lock.
  • Once a Thread got class level lock then it is allowed to execute any static synchronized method of that class.
  • While a Thread executing any static synchronized method the remaining Threads are not allowed to execute any static synchronized method of that class simultaneously.
  • But remaining Threads are allowed to execute normal synchronized methods, normal static methods, and normal instance methods simultaneously.
  • Class level lock and object lock both are different and there is no relationship between these two.

Synchronized block

1) If very few lines of the code required synchronization then it's never recommended to declare entire method as synchronized we have to enclose those few lines of the code within the synchronized block.
2)The main advantage of the synchronized block over the synchronized method is it reduces the waiting time of Thread and improves the performance of the system.

Example 1: To get a lock of current object we can declare synchronized block as follows. If Thread got lock of a current object then only it is allowed to execute this block. Synchronized(this){}

Example 2: To get the lock of a particular object 'b' we have to declare a synchronized block as follows. If thread got lock of 'b' object then only it is allowed to execute this block. Synchronized(b){}

Example 3: To get class level lock we have to declare synchronized block as follows. Synchronized(Display.class){} If thread got class level lock of Display then only it allowed to execute this block. 

Note: As the argument to the synchronized block we can pass either object reference or ".class file" and we can't pass primitive values as argument [because lock concept is dependent only for objects and classes but not for primitives].

Example:
Int x=b; Synchronized(x){} Output: Compile time error. Unexpected type. Found: int Required: reference . .

Example: 

Int x=b; Synchronized(x){}

 Output: Compile-time error. Unexpected type. Found: int Required: reference

Inter Thread communication (wait(),notify(), notifyAll())

  • Two Threads can communicate with each other by using wait(), notify(), and notifyAll() methods.
  • The Thread which is required updation it has to call wait() method on the required object then immediately the Thread will be entered into waiting state.
  • The Thread which is performing updation of the object is responsible to give notification by calling notify() method. After getting notification the waiting Thread will get those updations.
  • wait(), notify() and notifyAll() methods are available in Object class but not in Thread class because Thread can call these methods on any common object.
  • To call wait(), notify() and notifyAll() methods compulsory the current Thread should be owner of that object i.e., current Thread should has lock of that object i.e., current Thread should be in synchronized area. Hence we can call wait(), notify() and notifyAll() methods only from synchronized area otherwise we will get runtime exception saying IllegalMonitorStateException.
  • Once a Thread calls wait() method on the given object 1st it releases the lock of that object immediately and entered into the waiting state.
  • Once a Thread calls notify() (or) notifyAll() methods it releases the lock of that object but may not immediately. Except these (wait(),notify(),notifyAll()) methods there is no other place(method) where the lock release will be happen.
  • Once a Thread calls wait(), notify(), notifyAll() methods on any object then it releases the lock of that particular object but not all locks it has. public final void wait()throws InterruptedException public final native void wait(long ms)throws InterruptedException public final void wait(long ms, int ns)throws InterruptedException public final native void notify() public final void notifyAll()

Thread Not Releases Lock in case of : yield() join() sleep() 

 Thread Releases Lock in case of : wait() notify() notifyAll()


try
class ThreadA { public static void main(String[] args)throws InterruptedException { ThreadB b=new ThreadB(); b.start(); synchronized(b) { System.out.println("main Thread calling wait() method");//step-1 b.wait(); System.out.println("main Thread got notification call");//step-4 System.out.println(b.total); } } } class ThreadB extends Thread { int total=0; public void run() { synchronized(this) { System.out.println("child thread starts calcuation");//step-2 for(int i=0;i<=100;i++) { total=total+i; } System.out.println("child thread giving notification call");//step-3 this.notify(); } } } Output: main Thread calling wait() method child thread starts calculation child thread giving notification call main Thread got notification call 5050

Producer consumer problem

1) Producer(producer Thread) will produce the items to the queue and consumer(consumer thread) will consume the items from the queue. If the queue is empty then the consumer has to call wait() method on the queue object then it will be entered into the waiting state. 

 2) After producing the items producer Thread call notify() method on the queue to give notification so that consumer Thread will get that notification and consume items.

image11.png image12.png



Notify vs notifyAll()

  • We can use notify() method to give notification for only one Thread. If multiple Threads are waiting then only one Thread will get the chance and remaining Threads has to wait for further notification. But which Thread will be notify(inform) we can't expect exactly it depends on JVM.
  • We can use notifyAll() method to give the notification for all waiting Threads. All waiting Threads will be notified and will be executed one by one, because they are required lock

Note: On which object we are calling wait(), notify() and notifyAll() methods that corresponding object lock we have to get but not other object locks. Example:

image13

Which of the following statements are True ?

 Once a Thread calls wait() on any Object immediately it will entered into the waiting state without releasing the lock ?

 NO Once a Thread calls wait() on any Object it reduces the lock of that Object but may not immediately ? 

NO

 Once a Thread calls wait() on any Object it immediately releases all locks whatever it has and entered into waiting state ? 

NO

 Once a Thread calls wait() on any Object it immediately releases the lock of that particular Object and entered into waiting state? 

YES Once a Thread calls notify() on any Object it immediately releases the lock of that Object? NO Once a Thread calls notify() on any Object it releases the lock of that Object but may not immediately? YES

Deadlock 

  • If 2 threads are waiting for each other forever(without end) such type of situation(infinite waiting) is called deadlock.
  • There are no resolution techniques for deadlock but several prevention(avoidance) techniques are possible.
  • The synchronized keyword is the cause for deadlock hence whenever we are using synchronized keyword we have to take special care.
class A
{ public synchronized void foo(B b) { System.out.println("Thread1 starts execution of foo() method"); try { Thread.sleep(2000); } catch (InterruptedException e) {} System.out.println("Thread1 trying to call b.last()"); b.last(); } public synchronized void last() { System.out.println("inside A, this is last()method"); } } class B { public synchronized void bar(A a) { System.out.println("Thread2 starts execution of bar() method"); try { Thread.sleep(2000); } catch (InterruptedException e) {} System.out.println("Thread2 trying to call a.last()"); a.last(); } public synchronized void last() { System.out.println("inside B, this is last() method"); } } class DeadLock implements Runnable { A a=new A(); B b=new B(); DeadLock() { Thread t=new Thread(this); t.start(); a.foo(b);//main thread } public void run() { b.bar(a);//child thread } public static void main(String[] args) { new DeadLock();//main thread } } Output: Thread1 starts execution of foo() method Thread2 starts execution of bar() method Thread2 trying to call a.last() Thread1 trying to call b.last() //here cursor always waiting.

Note: If we remove at least one synchronized keyword then we won't get DeadLOck.Hence synchronized keyword in the only reason for DeadLock due to this while using synchronized keyword we have to handle carefully.

Daemon Threads

The Threads which are executing in the background are called daemon Threads. The main objective of daemon Threads is to provide support for non-daemon Threads like main Thread. Example: Garbage collector

Whenever the program runs with low memory the JVM will execute Garbage Collector to provide free memory. So that the main Thread can continue its execution.

  • We can check whether the Thread is daemon or not by using isDaemon() method of Thread class.
  • public final boolean isDaemon(); We can change the daemon nature of a Thread by using setDaemon () method. public final void setDaemon(boolean b);
  • But we can change daemon nature before starting Thread only. That is after starting the Thread if we are trying to change the daemon nature we will get R.E saying IllegalThreadStateException.
  • Default Nature : Main Thread is always non-daemon and we can't change its daemon nature because it's already started at the beginning only.
  • Main Thread is always non-daemon and for the remaining Threads, daemon nature will be inheriting from parent to child that is if the parent is daemon child is also daemon and if the parent is non daemon then child is also non-daemon.
  • Whenever the last non-daemon thread terminates automatically all daemon Threads will be terminated.

class MyThread extends Thread { } class DaemonThreadDemo { public static void main(String[] args) { System.out.println(Thread.currentThread().isDaemon()); MyThread t=new MyThread(); System.out.println(t.isDaemon()); 1 t.start(); t.setDaemon(true); System.out.println(t.isDaemon()); } } Output: false false RE:IllegalThreadStateException
class MyThread extends Thread
{ public void run() { for(int i=0;i<10 args="" catch="" daemonthreaddemo="" e="" i="" lazy="" main="" mythread="" nterruptedexception="" public="" static="" system.out.println="" t.setdaemon="" t="new" thread.sleep="" thread="" tring="" true="" try="" void="">1 t.start(); System.out.println("end of main Thread"); } } Output: End of main Thread . .
  • If we comment line 1 then both main & child Threads are non-Daemon , and hence both threads will be executed until there completion.
  • If we do not comment line 1 then main thread is non-Daemon and child thread is Daemon. Hence whenever the main Thread terminates automatically child thread will be terminated.

Lazy thread 

  • If we are commenting line 1 then both main and child Threads are non-daemon and hence both will be executed until they complete.
  • If we are not commenting line 1 then main Thread is non-daemon and child Thread is a daemon and hence whenever main Thread terminates automatically child Thread will be terminated.

Deadlock vs Starvation 

  • A long waiting of a Thread which never ends is called deadlock.
  • A long waiting of a Thread which ends at certain point is called starvation.
  • A low priority Thread has to wait until completing all high priority Threads.
  • This long waiting of Thread which ends at a certain point is called starvation.

How to kill a Thread in the middle of the line? We can call stop() method to stop a Thread in the middle then it will be entered into dead state immediately. public final void stop(); stop() method has been deprecated and hence not recommended to use.

suspend and resume methods

  • A Thread can suspend another Thread by using suspend() method then that Thread will be paused temporarily.
  • A Thread can resume a suspended Thread by using a resume() method then suspended Thread will continue its execution. public final void suspend(); public final void resume();
  • Both methods are deprecated and not recommended to use.

RACE condition

Executing multiple Threads simultaneously and causing data inconsistency problems is nothing but the Race condition we can resolve race conditions by using a synchronized keyword.

ThreadGroup

Based on functionality we can group threads as a single unit which is nothing but ThreadGroup. ThreadGroup provides a convenient way to perform common operations for all threads belongs to a perticular group. We can create a ThreadGroup by using the following constructors ThreadGroup g=new ThreadGroup(String gName); We can attach a Thread to the ThreadGroup by using the following constructor of Thread class Thread t=new Thread(ThreadGroup g, String name);

ThreadGroup g=new ThreadGroup("Printing Threads");
MyThread t1=new MyThread(g,"Header Printing"); MyThread t2=new MyThread(g,"Footer Printing"); MyThread t3=new MyThread(g,"Body Printing"); ----------- g.stop();

ThreadLocal(1.2 v)

We can use ThreadLocal to define local resources which are required for a particular Thread like DBConnections, counter variables etc., We can use ThreadLocal to define Thread scope like Servlet Scopes(page, request, session, application).

GreenThread

Java multiThreading concept is implementing by using the following 2 methods : GreenThread Model Native OS Model

GreenThread Model

The threads which are managed completely by JVM without taking support for the underlying OS, such type of threads are called Green Threads.

Native OS Model

  • The Threads which are managed with the help of underlying OS are called Native Threads.
  • Windows-based OS provides support for Native OS Model
  • Very few OS like SunSolaries provide support for GreenThread Model
  • Anyway GreenThread model is deprecated and not recommended to use.