X

Play AlgoQuiz

Rate Us :



Share with Friends :

Menu

Synchronization :

synchronized is a modifier applicable only for method and blocks but can't be apply for classes and variables. If a method or block declared as synchronized then at the time only one thread is allowed to execute that method or block on the given object.

The main advantage of synchronized keyword is to resolve data inconsistency problem. And the main limitation of synchronized keyword is that it increases waiting time of the thread and effects the performance of the system. Hence, if there is no specific requirement then it is never recommended to use synchronized keyword.

Every object in Java has a unique lock and synchronization concept internally implemented by using this lock concept. Whenever we are using synchronization then only lock concept will be applied. If a thread wants to execute any synchronized method on the given object then first it has to get the lock of that object. Once a thread gets a lock then it is allowed to execute any synchronized method on that object. Once synchronized method execution complete then automatically the lock will be released.

While a thread executing any synchronized method on the given object, the remaining threads are not allowed to execute any synchronized method on the same object simultaneously. But remaining threads are allowed to execute any non-synchronized methods simultaneously (lock concept is implemented based on object but not based on method).

class Valley
{
 public synchronized void wish(String s)
 {
     System.out.println("Hello...");
     System.out.println(s);
 }
}
class Algo extends Thread
{
 Valley v;
 String s;
 Algo(Valley v , String s)
 {
   this.v = v;
   this.s = s;
 }
 public void run()
 { 
   v.wish(s);
 }
}
class Example
{
 public static void main(String[ ] args)
  {
     Valley v1 = new Valley();
     Algo t1 = new Algo(v1 , "Alan");
     Algo t2 = new Algo(v1 , "Turing");
     t1.start();
     t2.start();  
  }
}

If we are not declaring wish() method as synchronized then both threads will be executed simultaneously and we can't expect exact output and we will get irregular output.

Hello...
Hello...
Turing
Alan


Hello... Alan Hello... Turing
Hello... Turing Hello... Alan

If we declare wish() method as synchronized then threads will be executed one by one so that we will get regular output.

Hello...
Alan
Hello...
Turing


Hello... Turing Hello... Alan

class Valley
{
 public synchronized void wish(String s)
 {
     System.out.println("Hello...");
     System.out.println(s);
 }
}
class Algo extends Thread
{
 Valley v;
 String s;
 Algo(Valley v , String s)
 {
   this.v = v;
   this.s = s;
 }
 public void run()
 { 
   v.wish(s);
 }
}
class Example
{
 public static void main(String[ ] args)
  {
     Valley v1 = new Valley();
     Valley v2 = new Valley();
     Algo t1 = new Algo(v1 , "Alan");
     Algo t2 = new Algo(v2 , "Turing");
     t1.start();
     t2.start();    
  }
}

Even though wish() method is synchronized we will get irregular output in the above case because threads are operating on different objects.

Hello...
Hello...
Turing
Alan


Hello... Alan Hello... Turing
Hello... Turing Hello... Alan

Whenever multiple threads are operating on same object then only synchronization takes place. If multiple threads are operating on multiple objects then there is no impact of synchronization.


Class Level Lock :

Every class in Java has an unique lock. If a thread wants to execute a static synchronized method then it require class level lock. While a thread executing a static synchronized method then the remaining threads are not allowed to execute any static synchronized method of that class simultaneously but remaining threads are allowed to execute the following methods simultaneously :

  • normal static methods




  • normal instance methods




  • synchronized instance methods




Note :

There is no link between object level lock and class level lock, both are independent & different from each other.


Synchronized Block :

If very few lines of code requires to implement synchronization then it is never recommended to declare entire method as synchronized. We have to declare those few lines of code inside the synchronized block. The main advantage of synchronized block over synchronized method is that it reduces the waiting time of the thread and improves performance of the system.

We can declare synchronized block to get current object lock as follows :

synchronized(this)
{

}

If thread got lock of current object then it is allowed to execute this block.


To get lock of a particular object 'b' we can declare synchronized block as follows :

synchronized(b)
{

}

If thread got lock of object 'b' then only it is allowed to execute this block.


To get class level lock we can declare synchronized block as follows :

synchronized(classname.class)
{

}

If a thread got class level lock of classname.class then only it is allowed to execute this block.


Synchronized block concept is applicable only for objects and classes but not for primitives otherwise we will get compile time error.

int a = 10;
synchronized(a)
{

}
/*Compile time error : unexpected type
                       found : int
                       required : reference */

Every objects in Java has a unique lock, but a thread can acquire more than one lock at a time (for different objects).

class A
{
 synchronized m1()
 {
   B b = new B();
   b.m2();
 }
}

class B
{
 synchronized m2()
 {
 
 }
} 

For a particular thread we have two locks (lock of A and lock of B).


Inter Thread Communication :

Two threads will communicate with each other by using wait() , notify() and notifyAll() methods. The thread which require to update has to call wait() method. The thread which is responsible to update then it has to call notify() method. wait() , notify() and notifyAll() methods are available in Object class but not in Thread class, hence threads are required to call these methods on any shared object. If a thread wants to call wait() , notify() and notifyAll() methods then it is compulsory that the thread should be the owner of the object i.e. the thread has to get lock of that object i.e. the 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.

If a thread calls wait() method, it releases the lock immediately and enters into waiting state. The thread releases lock of only current object but not all locks. After calling notify() and notifyAll() methods, thread releases the lock but may not immediately. Except these wait() , notify() and notifyAll() there is no other case where thread releases the lock.

Signature of these methods :


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()

Example :

class Algo extends Thread { int tol = 0; public void run() { synchronized(this) { System.out.println("Child thread starts notification"); for(int i = 1 ; i <= 100 ; i++) { tol = tol+i; } System.out.println("Child thread trying to give notification"); this.notify(); } } } class Example { public static void main(String[ ] args) throws InterruptedException { Algo t = new Algo(); t.start(); synchronized(t) { System.out.println("Main thread trying to call wait()"); t.wait(); System.out.println("Main thread got notification"); System.out.println(t.tol); } } } //save as : Example.java //compile as : javac Example.java //run as : java Example

Output :

Main thread trying to call wait() Child thread starts notification Child thread trying to give notification Main thread got notification 5050

notify() VS notifyAll() :

We can use notify() method to notify only one waiting thread but which waiting thread will be notified we can't expect exactly. All remaining threads have to be waiting for their notification.

But in the case of notifyAll() method all waiting threads will be notified but the thread will be executed one by one.


Deadlock :

If two threads are waiting for each other forever, such type of situation is called deadlock. There is no resolution technique for deadlock but several prevention techniques are possible.

Example :

class Algo { public synchronized void am(Valley v) { System.out.println("Thread starts Algo execution"); try { Thread.sleep(2000); } catch(InterruptedException e) { System.out.println(e); } System.out.println("Thread trying to catch v's c()"); v.c(); } public synchronized void c() { System.out.println("c() in Algo"); } } class Valley { public synchronized void bm(Algo a) { System.out.println("Thread starts Valley execution"); try { Thread.sleep(2000); } catch(InterruptedException e) { System.out.println(e); } System.out.println("Thread trying to catch a's c()"); a.c(); } public synchronized void c() { System.out.println("c() in Valley"); } } class Example extends Thread { Algo a = new Algo(); Valley v = new Valley(); public void m() { this.start(); a.am(v); //executed by main thread } public void run() { v.bm(a); //executed by child thread } public static void main(String[ ] args) { Example t = new Example(); t.m(); } } //save as : Example.java //compile as : javac Example.java //run as : java Example

Output :

Thread starts Algo execution Thread starts Valley execution Thread trying to catch v's c() Thread trying to catch a's c() .............................

synchronized keyword is the only one reason for deadlock, hence while using synchronized keyword we have to take much care.


Deadlock VS Starvation :

In the case of deadlock waiting never ends. A long waiting of a thread which ends at certain point of time is called starvation. A least priority thread has to wait until completion of all threads but this long waiting should compulsory ends at certain point of time. Hence, a long waiting which never ends is called Deadlock where as a long waiting which ends at certain point of time is called Starvation.


Daemon threads :

The threads which are executing in the background are called Daemon threads, Example - Garbage Collector.

The main objective of Daemon thread is to provide support for non-Daemon threads. We can check whether the thread is Daemon or not by using isDaemon() method.

public final boolean isDaemon()

We can change Daemon nature of a thread by using setDaemon() method.

public final void setDaemon(boolean b)

We can change Daemon nature of a thread before starting it's execution because if we are trying to change after start of execution of a thread then we will get runtime exception saying IllegalThreadStateException. The main thread is always non-Daemon and it is not possible to change it's Daemon nature.


Default Nature :

By default main method is always non-Daemon but for all the remaining threads Daemon nature will be inheriting from the parent to child i.e. if the parent is Daemon then the child will also be Daemon and if the parent is non-Daemon then the child will also be non-Daemon.

Whenever the last non-Daemon thread terminates then all the Daemon threads will be terminated automatically.

Example :

class Algo extends Thread { public void run() { for(int i = 0 ; i <= 10 ; i++) { System.out.println("Child Thread"); try { Thread.sleep(2000); } catch(InterruptedException e) { System.out.println(e); } } } } class Example { public static void main(String[ ] args) { Algo t = new Algo(); t.setDaemon(true); //Line 1 t.start(); System.out.println("End of main"); } }

If we are commenting Line 1 then both main and child threads are non-Daemon and both will be executed until their completion.

If we are not commenting Line 1 then main thread is non-Daemon and child thread is daemon. Hence, whenever main thread terminates then automatically child thread will be terminated.

End of main
Child Thread


Child Thread End of main
End of main

Java multithreading concept is implemented by using the following two models :

  • Green Thread Model




  • Native OS Model




Green Thread Model :-

The thread which is managed completely by JVM without taking underline OS support is called green thread. Very few OS like Sun Solaris provide support for green thread model. Anyway green thread model is deprecated and hence, not recommended to use.


X

deprecated :

It expresses disapproval.

Native OS Model :-

The thread which is managed by the JVM with the help of underline OS, is called native OS model. All Windows based OS provide support for native OS model.


How to kill a thread :

We can kill or stop a thread execution by using stop() method of Thread class. If we call stop() method then immediately running thread will enter into dead state. It is a deprecated method and hence, not recommended to use.

public void stop();

Suspending and Resuming a thread :

We can suspend a thread by using suspend() method of Thread class then immediately thread will enter into suspended state and we can resume a suspended thread by using resume() method of Thread class then suspended thread can continue it's execution. These methods are deprecated and hence, not recommended to use.

public void suspend();
public void resume();


X

MiniDoll :

MiniDoll is an application to learn with fun. You can play it to solve some tricky questions related to Java Programming. Either enjoy playing it alone or discuss with your friends to solve it. It is a simple approach to learn by solving questions. This application has different topics of Java and each topic is divided into three phases. Start solving from initial topic to final topic and by the end of every topic you can boost your concept of that topic.