Home > Java, Multithreading > Synchronization

Synchronization


When a thread starts working on some critical work he locks the room (say monitor) using synchronized keyword. So no other thread can enter into the room until the current thread finish his work.

You can synchronized either an object or a method in following ways

1. Synchronize an object

public void run() {
	synchronized(target) { // synchronized object
	:
	}
}

2. Synchronize a method

public synchronized void myMethod() {
	:
}
//or
public void myMethod() {
	Synchronized(this){
	:
	}
}

Note :

If you are synchronizing a static method then it’ll take lock over complete class.
If you place synchronized block over the same object on multiple places and one of the thread had already entered into one of them, no other thread can enter into any of the synchronized block until first thread comes out.

public class SynchoTest {
	private Integer a = 10;

	public void acquire(){
		synchronized(a){
			print("acquire()");
			try{
				Thread.sleep(10000);
				print("I have awoken" + a);
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
		print("Leaving acquire()");
	}

	public void modify(int n){
		this.a=n;
		print("new value" + a);
	}

	public void display(){
		print("a=" + a);
	}
	:
}

For above program, I am starting 3 threads. Thread A calls method acquire(), Thread B calls modify(97), and Thread C calls display().

Output:

2012-03-06 07:48:10.038 :: A: acquire()
2012-03-06 07:48:10.038 :: B: new value97
2012-03-06 07:48:10.038 :: C: a=97
2012-03-06 07:48:20.054 :: A: I have awoken
2012-03-06 07:48:20.054 :: A: 97
2012-03-06 07:48:20.054 :: A: Leaving acquire()

What have you noticed in above output? When A entered in his critical section, a’s value was 10. But when it went to print it, B already changed a’s value. So A prints new value of a ie 97.

Now do some small changes

public void modify(int n){
	print("Entered in modfy");
	synchronized(a){
		this.a=n;
		print("new value" + a);
	}
}

Output:

2012-03-06 07:51:46.19 :: A: acquire()
2012-03-06 07:51:46.19 :: B: Entered in modfy
2012-03-06 07:51:46.19 :: C: a=10
2012-03-06 07:51:56.206 :: A: I have awoken
2012-03-06 07:51:56.206 :: A: 10
2012-03-06 07:51:56.206 :: A: Leaving acquire()
2012-03-06 07:51:56.206 :: B: new value97

This time everything is fine. why so?

If there are many synchronized blocks on same object and any thread has entered into one of the synchronized block then no other thread can enter into any synchronized block on the same object. synchronized checks happens-before condition then either it acquire lock or waits until another thread releases lock or get interrupted.

synchronized blocks on different-2 objects has no interrelation. Any thread can enters into any synchronized block. Synchronized(a) and synchronized(this) are also non-related.
Lets play with some more code:

public void modify(int n){
	this.a=n;
	print("new value" + a);
}
public void display (int n){
	print("a=" + a);
	synchronized(a){
		try{
			Thread.sleep(1000);
			print("a=" + a);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
}

Output:

a=34
new value45
a=45

Code Postmortem

Thread 1 inserts into synchronized block of display(). It takes lock on a. Thread 2 insert into modify(). But there is no new synchronized block. So it doesn’t check whether some thread has taken lock on a before. So it allows modification in a. Thus display() prints modified value of a.

If I makes modify() synchronized even, it doesn’t change the output.

public synchronized void modify(int n){
	this.a=n;
	print("new value" + a);
}

Because making modify() synchronized ensures that no more than 1 thread can call modify() at a time. It is not related to synchronized(a).

Lets read some more important points about synchronization.

If you are starting threads on 2 separate objects then there is no relation between those threads because both objects use different memory address. Hence their synchronized blocks are also not related.
synchronized(a) should not contain any statement modifying value of a. You’ll notice it when you’ll read about wait(),notify() etc. However it is allowed.

Synchronizing a method or using synchronized(this) everywhere in class is not good practice. Because it blocks all threads to access any synchronized block. Taking lock on necessary field is always a good practice.

Deadlock

I tried to code many programs which can help me to understand race condition, starvation, and deadlock practically. But I failed. Unknowingly I made this program which creates deadlock due improper synchronization.

public synchronized void acquire() throws Exception{
	Thread.sleep(5000);
	synchronized(lock){
		wait(1);
	}
}

public synchronized void modify() throws Exception{
	Thread.sleep(5000);
	synchronized(lock){
		wait(1);
	}
}

I added a tracer who explained me why both threads were getting blocked. You can integrate separate java thread tracer with your other threading programs.

Refer the output below to understand how improper nested monitoring took lock.

Output:

A:8
B:9
2012-03-07 19:54:57.625 :: [A:RUNNABLE,B:RUNNABLE]
2012-03-07 19:54:57.788 :: [A:RUNNABLE,B:BLOCKED]
2012-03-07 19:54:57.804 :: [A:TIMED_WAITING,B:BLOCKED]
2012-03-07 20:54:59.888 :: [A:RUNNABLE,B:BLOCKED]
2012-03-07 19:55:02.787 :: [A:TIMED_WAITING,B:TIMED_WAITING]
2012-03-07 19:55:02.788 :: [A:BLOCKED,B:TIMED_WAITING]
2012-03-07 19:55:07.787 :: [A:BLOCKED,B:RUNNABLE]
2012-03-07 19:55:07.787 :: [A:BLOCKED,B:BLOCKED]
Both threads are blocked
Deadlock detected in
Thread id: 9
Thread id: 8

Proper synchronization:

public void acquire() throws Exception{
	Thread.sleep(5000);
	synchronized(lock){
		lock.wait(1);
	}
}

public void modify() throws Exception{
	Thread.sleep(5000);
	synchronized(lock){
		lock.wait(1);
	}
}

You can solve this deadlock in another way as well. Its up to your need.

Advertisements
Categories: Java, Multithreading
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: