Core Java

Java Synchronized Blocks Example

In this post, we feature a comprehensive article on Java Synchronized Blocks. Java synchronized keyword marks a block or method a critical section. A critical section is where one and only one thread is executing at a time, and the thread holds the lock for the synchronized section.

Java is multi-threaded language where multiple threads runs parallel to complete their execution. It makes two kinds of errors possible: thread interference and memory consistency errors. We need to synchronize the shared resources to ensure that at a time only one thread is able to access the shared resource in order to prevent these errors.

Java provide two synchronization idioms:

  • Block synchronization (Statement(s) synchronization)
  • Methods synchronization

1. Java Synchronized Blocks

If we only need to execute some subsequent lines of code not all lines of code within a method, then we should synchronize only block of the code within which required instructions are exists.

The general syntax for writing a synchronized block is as follows:

Synchronized block

synchronized( lockObject )
{
   // synchronized statements
}

When a thread wants to execute synchronized statements inside the synchronized block, it MUST acquire the lock on lockObject‘s monitor. At a time, only one thread can acquire the monitor of a lock object. So all other threads must wait till this thread, currently acquired the lock, finish it’s execution and release the lock.

In this way, synchronized keyword guarantees that only one thread will be executing the synchronized block statements at a time, and thus prevent multiple threads from corrupting the shared data inside the block.

1.1 Java synchronized block example

Lets suppose there is a method that contains 50 lines of code but there are only 5 lines (one after one) of code which contain critical section of code i.e. these lines can modify (change) the Object’s state. So we only need to synchronize these 5 lines of code method to avoid any modification in state of the Object and to ensure that other threads can execute rest of the lines within the same method without any interruption.

In Example01, we have a Number with a method printNumbers(). The code in printNumbers() method is inside synchronized block.

Number.java

public class Number {
    void printNumbers(int n) throws InterruptedException
    {
        synchronized (this)
        {
            for (int i = 1; i <= n; i++)
            {
                System.out.println(Thread.currentThread().getName() + " :: "+  i);
                Thread.sleep(500);
            }
        }
    }
}

Now we create two threads which start executing the printNumbers() method exactly at same time. Due to block being synchronized, only one thread is allowed to access and other thread has to wait until first thread is finished.

Main.java

public class Main
{
    public static void main(String args[])
    {
        final Number number = new Number();

        //first thread
        Runnable r = new Runnable()
        {
            public void run()
            {
                try {
                    number.printNumbers(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        new Thread(r, "ONE").start();
        new Thread(r, "TWO").start();
    }
}

The output:

ONE :: 1
ONE :: 2
ONE :: 3
TWO :: 1
TWO :: 2
TWO :: 3

Lets see another example for synchronized block. Here in Example02 we have class NameList as this:

NameList.java

public class NameList {
    String name = "";
    public int count = 0;

    public void addName(String str, java.util.List list)
    {
        // Only one thread is permitted
        // to change name at a time.
        synchronized(this)
        {
            name = str;
            count++;  // how many threads change the name.
        }

        // All other threads are permitted
        // to add name into list.
        list.add(str);
    }

    public int getCount(){
        return count;
    }
}

Here is the Main class:

Main.java

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main (String[] args)
    {
        NameList gk1 = new NameList();
        NameList gk2 = new NameList();
        List list = new ArrayList();
        gk1.addName("javaCodeGeek1", list);
        gk2.addName("javaCodeGeek2", list);
        System.out.println("Thread1: " + gk1.name + ", " + gk1.getCount() + "\n");
        System.out.println("Thread2: " + gk2.name + ", " + gk2.getCount() + "\n");
    }
}

The output:

Thread1: javaCodeGeek1, 1

Thread2: javaCodeGeek2, 1

2. Java synchronized method

The general syntax for writing a synchronized method is as follows:

Synchronized method

<access modifier> synchronized method( parameters )
{
    // synchronized code
}

Similar to synchronized block, a thread MUST acquire the lock on the associated monitor object with synchronized method. If a Object is visible to more than one threads, all reads or writes to that Object’s fields are done through the synchronized method.

In case of synchronized method, the lock object is:

  • ‘.class’ object – if the method is static.
  • ‘this’ object – if the method is not static. ‘this’ refer to reference to current object in which synchronized method is invoked.

Java synchronized keyword is re-entrant in nature it means if a synchronized method calls another synchronized method which requires same lock then current thread which is holding lock can enter into that method without acquiring lock.

2.1 Java synchronized method example

We change the previous example, we can apply synchronized keyword at printNumber() method and it will make the method as synchronized.

Number.java

public class Number {
    synchronized void printNumbers(int n) throws InterruptedException {
        for (int i = 1; i <= n; i++) {
            System.out.println(Thread.currentThread().getName() + " :: " + i);
            Thread.sleep(500);
        }
    }
}

The output:

ONE :: 1
ONE :: 2
ONE :: 3
TWO :: 1
TWO :: 2
TWO :: 3

3. Need of Synchronization example

Now we see some examples to show situations where we need synchronization. Here we have a class named Line. Example01 illustrates multiple threads are executing on the same Object at same time without synchronization.

Line.java

public class Line {
    public void getLine()
    {
        for (int i = 0; i < 3; i++)
        {
            System.out.println(i);
            try
            {
                Thread.sleep(400);
            }
            catch (Exception e)
            {
                System.out.println(e);
            }
        }
    }
}

We create class Train as following:

Train.java

public class Train extends Thread {
    // reference to Line's Object.
    Line line;

    Train(Line line)
    {
        this.line = line;
    }

    @Override
    public void run()
    {
        line.getLine();
    }
}

If multiple threads(trains) will try to access this unsynchronized method, they all will get it. So there is chance that Object’s state will be corrupted.

Now in Main class we create threads that are sharing the same Object:

Main.java

public class Main {
    public static void main(String[] args)
    {
        // Object of Line class that is shared 
        // among the threads. 
        Line obj = new Line();

        // creating the threads that are 
        // sharing the same Object. 
        Train train1 = new Train(obj);
        Train train2 = new Train(obj);

        // threads start their execution. 
        train1.start();
        train2.start();
    }
}

The output:

0
0
1
1
2
2

There can be two trains which need to use same Object at same time so there is chance of collision. Therefore to avoid collision we need to synchronize the the line in which multiple want to run.

Now in Example02 we show that multiple threads can execute the same method but in synchronized way:

Line.java

public class Line {
    synchronized public void getLine()
    {
        for (int i = 0; i < 3; i++)
        {
            System.out.println(i);
            try
            {
                Thread.sleep(400);
            }
            catch (Exception e)
            {
                System.out.println(e);
            }
        }
    }
}

The Train class like this:

Train.java

public class Train extends Thread {
    // Reference variable of type Line.
    Line line;

    Train(Line line)
    {
        this.line = line;
    }

    @Override
    public void run()
    {
        line.getLine();
    }
}

Again in Main class we create threads that are sharing the same Object:

Main.java

public class Main {
    public static void main(String[] args)
    {
        Line obj = new Line();

        // we are creating two threads which share
        // same Object.
        Train train1 = new Train(obj);
        Train train2 = new Train(obj);

        // both threads start executing .
        train1.start();
        train2.start();
    }
}

The output:

0
0
1
2
0
1
2
2

Important points:

  • When thread enters into synchronized instance method or block, it acquires Object level lock and when it enters into synchronized static method or block it acquires class level lock.
  • Java synchronization will throw null pointer exception if Object used in synchronized block is null. For example, If in synchronized(instance) , instance is null then it will throw null pointer exception.
  • Java synchronized method run very slowly so you should synchronize the method when it is absolutely necessary because it may degrade the performance.

4. Download the source code

Download
You can download the full source code of this example here: Java Synchronized Blocks Example

Firouzeh hejazi

A self-motivated and hard-working developer with more than 4 years of extensive experience in developing software in java platforms. A multi-skilled and problem-solving engineer who has participated in implementing a range of applications in different roles. Possess a MSc in Knowledge Engineering and Decision Science.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
debugchaos
debugchaos
3 years ago

The output of the last example seems incorrect. The below is the correct one:
0
1
2
0
1
2

Back to top button