Synchronization

  • There will be some situations where two or more threads want to access the same resource, there need some way to ensure that the resource will be used by one at a time this is done by Synchronization.
  • The key for Synchronization is the concept of monitor.
  • A monitor is an object that is used as a mutually exclusive lock by allowing only one thread to own a monitor at a given time.

  • when a thread acquires a lock, it is said to be entered the monitor,all other threads will be attempting to locked monitor but it will be suspended until the first thread exits the monitor.

Using Synchronized Methods

  • To enter monitor's object we have to call a method which is modified by the synchronized keyword.
  • When a thread is inside a synchronized method other threads have to wait until it returns from the method.
// This program is not synchronized.
class Callme
 {
void call(String msg) 
{
 System.out.print("[" + msg);
 try 
{
 Thread.sleep(1000);
 } 
catch(InterruptedException e)
 {
 System.out.println("Interrupted");
 }
 System.out.println("]");
 }
}

class Caller implements Runnable 
{
 String msg;
 Callme target;
 Thread t;
 public Caller(Callme targ, String s) 
{
 target = targ;
 msg = s;
 t = new Thread(this);
 t.start();
 }
 public void run() 
{
 target.call(msg);
 }
}
public class Simple 
{
 public static void main(String args[]) 
{
 Callme target = new Callme();
 Caller ob1 = new Caller(target, "Hello");     //three objects are accessing call(msg) at the same time called race condition
 Caller ob2 = new Caller(target, "Synchronized");
 Caller ob3 = new Caller(target, "World");
 // wait for threads to end
 try 
{
 ob1.t.join();
 ob2.t.join();
 ob3.t.join();
 } catch(InterruptedException e) 
{
 System.out.println("Interrupted");
 }
 }
}

Output:

[Hello[World[Synchronized]

]

]

In this example sleep() and call() methods are used to switch from one thread to another where all three threads are try to call same method with same object at a same time which is called as race condition as there is nothing to stop calling same method.

//with synchronization 
class Callme
 {
synchronized void call(String msg) //synchronized makes only one thread to access a method at a same time.
{
 System.out.print("[" + msg);
 try 
{
 Thread.sleep(1000);
 } 
catch(InterruptedException e)
 {
 System.out.println("Interrupted");
 }
 System.out.println("]");
 }
}

Output:

[Hello]

[World]

[Synchronized]

The synchronized Statement

There will be some situations where synchronized keyword will not be useful.

Ex: The class where all the objects are trying call a method is not given by us so we don't have access to add synchronized to that method. Where it is not using synchronized methods to access by two or more objects.

Then we have to call all those type of methods in synchronized block as follows:

Syntax:

synchronized(objRef)

{

// statements to be synchronized

}

objRef- It is the reference of object which ensures that call to a synchronized methods which are the members of that object reference.

//example for using synchronized block

class Callme
{
void call(String msg)
{
System.out.print("[" + msg);
try
{
Thread.sleep(1000);
}
catch(InterruptedException e)
{
System.out.println("Interrupted");
}
System.out.println("]");
}
}

class Caller implements Runnable
{
String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s)
{
target = targ;
msg = s;
t = new Thread(this);
t.start();
}
public void run()
{
synchronized(target)  //synchronized block
{
target.call(msg);
}
}
}
public class Simple
{
public static void main(String args[])
{
Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello"); //three objects are accessing call(msg) at the same time called race condition
Caller ob2 = new Caller(target, "Synchronized");
Caller ob3 = new Caller(target, "World");
// wait for threads to end
try
{
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch(InterruptedException e)
{
System.out.println("Interrupted");
}
}
}

Output:

[Hello]

[World]

[Synchronized]

Inter-thread Communication

In java threads provide benefit of do away with polling.

  • polling-

Polling is aloopwhere it have to bewait until the condition is truewhich wastes the CPU time.

To avoid polling java provides inter thread communication by usingwait( ), notify( ), andnotifyAll( )methods.

  • wait( ) tells the calling thread to give up the monitor and go to sleep until some other thread enters the same monitor and calls notify( ) or notifyAll( ).
  • notify( ) wakes up a thread that called wait( ) on the same object.

  • notifyAll( ) wakes up all the threads that called wait( ) on the same object. One of the threads will be granted access

The general form of all these methods are:

final void wait( ) throws InterruptedException

final void notify( )

final void notify All( )

// A correct implementation of a producer and consumer.
class Q 
{
 int n;
 boolean valueSet = false;
 synchronized int get() 
 {
 while(!valueSet)
 try 
 {
 wait();
 }
  catch(InterruptedException e) 
 {
 System.out.println("InterruptedException caught");
 }
 System.out.println("Got: " + n);
 valueSet = false;
 notify();
 return n;
 }
 synchronized void put(int n)
  {
  while(valueSet)
 try {
 wait();
 } 
 catch(InterruptedException e) 
 {
 System.out.println("InterruptedException caught");
 }
 this.n = n;
 valueSet = true;
 System.out.println("Put: " + n);
 notify();
 }
}
class Producer implements Runnable 
{
 Q q;
 Producer(Q q)
  {
 this.q = q;
 new Thread(this, "Producer").start();
 }
 public void run() 
 {
 int i = 0;
 while(true) 
 {
 q.put(i++);
 }
 }
}
class Consumer implements Runnable 
{
 Q q;
 Consumer(Q q) 
 {
 this.q = q;
 new Thread(this, "Consumer").start();
 }
 public void run() 
 {
 while(true)
  {
 q.get();
 }
 }
}
public class PCFixed 
{
 public static void main(String args[]) 
 {
 Q q = new Q();
 new Producer(q);
 new Consumer(q);
 System.out.println("Press Control-C to stop.");
 }
}

Output:

Put: 1

Got: 1

Put: 2

Got: 2

Put: 3

Got: 3

Put: 4

Got: 4

Put: 5

Got: 5

Deadlock

It is error which occurs in multitasking where two threads have a circular dependency on pair of objects.

EX:

one thread enters the monitor on object X and another thread monitors the object Y.

If X tries to call the synchronized method on Y, it will block as well as if Y tries to call the synchronized method on X the thread waits forever.

because to access X, it would have to release its own lock on Y so that the first thread could complete.

Deadlock is a difficult error to debug for two reasons

  • In general, it occurs only rarely, when the two threads time-slice in just the right way.
  • It may involve more than two threads and two synchronized objects.
// An example of deadlock.
class A {
 synchronized void foo(B b) {
 String name = Thread.currentThread().getName();
 System.out.println(name + " entered A.foo");
 try {
 Thread.sleep(1000);
 } catch(Exception e) {
 System.out.println("A Interrupted");
 System.out.println(name + " trying to call B.last()");
 b.last();
 }
 synchronized void last() {
 System.out.println("Inside A.last");
 }
}
class B {
 synchronized void bar(A a) {
 String name = Thread.currentThread().getName();
 System.out.println(name + " entered B.bar");
 try {
 Thread.sleep(1000);
 } catch(Exception e) {
 System.out.println("B Interrupted");
 }
 System.out.println(name + " trying to call A.last()");
 a.last();
 }
 synchronized void last() {
 System.out.println("Inside A.last");
 }
}
class Deadlock implements Runnable {
 A a = new A();
 B b = new B();
 Deadlock() {
 Thread.currentThread().setName("MainThread");
 Thread t = new Thread(this, "RacingThread");
 t.start();
 a.foo(b); // get lock on a in this thread.
 System.out.println("Back in main thread");
 }
 public void run() {
 b.bar(a); // get lock on b in other thread.
 System.out.println("Back in other thread");
 }
 public static void main(String args[]) {
 new Deadlock();
 }
}

Output:

MainThread entered A.foo

RacingThread entered B.bar

MainThread trying to call B.last()

RacingThread trying to call A.last()

results matching ""

    No results matching ""