Synchronization

This is Third Article in Series of Articles on Java 8 Concurrency Tutorial.

Synchronization

Threads communicate primarily by sharing access to fields and the objects reference fields refer to. This form of communication is extremely efficient, but makes two kinds of errors possible: thread interference and memory consistency errors. The tool needed to prevent these errors is synchronization.

There are many situations in which multiple threads must share access to common objects.
And There may be a situation when multiple threads try to access the same resource, Then they can produce inconsistent result due to concurrency issues.

e.g In below example two Threads are trying to increment counter by 1000, So after end of execution. Vlaue of counter should be 2000, but that not the case.

Inconsistent result due to concurrency - Without Synchronization
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

public class SynchronizedMethodExample {

private static int counter= 0;
private static void increment()
{
counter = counter+1;
}

public static void main(String[] args) throws InterruptedException {

System.out.println("Main start!!");
Thread t1 = new Thread(new Runnable() {

public void run() {
for (int i = 0; i < 1000; i++) {
increment();

}

}
});

Thread t2 = new Thread(new Runnable() {

public void run() {
for (int i = 0; i < 1000; i++) {
increment();
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Counter " + counter);
System.out.println("Main End");
}
}

If you check output , The value of Conter is not exactly equal to 2000.

Synchronization idioms

The Java programming language provides two basic synchronization idioms: synchronized methods and synchronized statements.

Synchronized Methods

To make a method synchronized, simply add the synchronized keyword to its declaration.
Synchronized method is used to lock an object for any shared resource. When a thread invokes a synchronized method, it automatically acquires the lock for that object and releases it when the thread completes its task.

If in above exapmle we make increment method as Synchronized, then has two effects:

First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.

Synchronized Method Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

public class SynchronizedMethodExample {

private static int counter= 0;
private static synchronized void increment()
{
counter = counter+1;
}
public static void main(String[] args) throws InterruptedException {

System.out.println("Main start!!");
Thread t1 = new Thread(new Runnable() {

public void run() {
for (int i = 0; i < 1000; i++) {
increment();

}

}
});
Thread t2 = new Thread(new Runnable() {

public void run() {
for (int i = 0; i < 1000; i++) {
increment();
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Counter " + counter);
System.out.println("Main End");
}
}

Synchronized Blocks

Each time We do not have to synchronize a whole method. Sometimes it is preferable to synchronize only part of a method. Java synchronized blocks inside methods makes this possible.The increment method Can implemented by using Synchronized Blocks

Synchronized Block Example
1
2
3
4
5
6
7

private void increment()
{
synchronized(this){
counter = counter+1;
}
}

It is better to use Synchronized Blocks using private object, rather than putting it on a method.

Putting it on the method means you are using the lock of the object itself to provide thread safety. With this kind of mechanism, it is possible for a malicious user of your code to also obtain the lock on your object, and hold it forever, effectively blocking other threads. A non-malicious user can effectively do the same thing inadvertently.

If you use the lock of a private data member, you can prevent this, since it is impossible for a malicious user to obtain the lock on your private object.

Synchronized Block Example
1
2
3
4
5
6
7
8
9

private final Object lockObject = new Object();

private void increment()
{
synchronized(lockObject){
counter = counter+1;
}
}
Share Comments