Provide Best Programming Tutorials

Thread Synchronization

Thread Synchronization

Thread synchronization is to coordinate the execution of the dependent threads.A shared resource may become corrupted if it is accessed simultaneously by multiple threads.

The following example demonstrates the problem.

Suppose you create and launch 100 threads, each of which adds a penny to an account.Define a class named Account to model the account, a class named AddMoney to add a penny to the account, and a main class that creates and launches threads.

Below program actually will not change the balance to 100 as we expected. Instead the balance maybe any integer with 100.

package multithreading.threadCorporation;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadCorporationDemo {

    private static Account account = new Account();

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 0; i < 100; i++) {
            executorService.execute(new AddMoney());
        }


        executorService.shutdown();

        //waiting for all the thread to shutdown
        while (!executorService.isTerminated()) {

        }

        System.out.println(account.balance);

    }

    private static class Account {
        private int balance = 0;


        public void deposit(int amount) {
            try {
                int newBalance = balance + amount;

                Thread.sleep(5);
                balance = newBalance;

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }

    private static class AddMoney implements Runnable {

        @Override
        public void run() {
            account.deposit(1);

        }
    }
}

This is because multipy threads try to modify the same target: balance in method.

For example a thread just finish executing line 3 and enter sleep because of line 5.

let’s suppose before this thread sleep the newBalance is modified to 5 when he woke up this newBalance is changed to 2 because during his sleeping time another thread change it because this thread don’t “protect” the newBalance. Thus leads to a mess if there are multipy threads.

1 public void deposit(int amount) {
2            try {
3                int newBalance = balance + amount;
4
5                Thread.sleep(5);
6                balance = newBalance;
7
8            } catch (InterruptedException e) {
9                e.printStackTrace();
10       }
11  }

In order to let things go as we expected we need to protect these critical area for example here is the deposit method.

Java provides us server tools for helping us doing so.

synchronized keyword

The keyword synchronized marks the “critical area” as a protected area just like a lock in you house.Unless This thread finish using this “critical area” otherwise other thread have to wait outside. Thus we can avoid the mess we mentioned above.

public synchronized void deposit(double amount)

public synchronized void deposit(int amount) {
    try {
        int newBalance = balance + amount;

        Thread.sleep(5);
        balance = newBalance;

    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Invoking a synchronized instance method of an object acquires a lock on the object, and invoking a synchronized static method of a class acquires a lock on the class. A synchronized statement can be used to acquire a lock on any object, not just this object, when executing a block of the code in a method.

The general form of a synchronized statement is as follows:

synchronized (expr) {
    statements;
}

The expression expr must evaluate to an object reference. If the object is already locked by another thread, the thread is blocked until the lock is released. When a lock is obtained on the object, the statements in the synchronized block are executed and then the lock is released.

Synchronization Using Locks

By using Lock we can achive the same goal as synchronized.

Let’s take a look at example below:

package multithreading.lockDemo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo {

    private static Account account = new Account();
    private static Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 0; i < 100; i++) {
            executorService.execute(new AddMoney());
        }
        executorService.shutdown();
        //waiting for all the thread to shutdown
        while (!executorService.isTerminated()) {

        }

        System.out.println(account.balance);
    }

    private static class Account {
        private int balance = 0;
        
        public  void deposit(int amount) {
            try {
                lock.lock();
                int newBalance = balance + amount;

                Thread.sleep(5);
                balance = newBalance;

            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }

    private static class AddMoney implements Runnable {

        @Override
        public void run() {
            account.deposit(1);
        }
    }
}

we create a new Lock instance by using this statement:

private static Lock lock = new ReentrantLock();

then in the depostit method we using it

1 public  void deposit(int amount) {
2           try {
3                lock.lock();// Acquire the lock
4                int newBalance = balance + amount;
5   
6                Thread.sleep(5);
7                balance = newBalance;
8
9            } catch (InterruptedException e) {
10                e.printStackTrace();
11            }finally {
12                lock.unlock();// Release the lock
13            }
14        }

Line 3 accquire a this lock and line 12 release this lock.

In general, using synchronized methods or statements is simpler than using explicit locks for mutual exclusion. However, using explicit locks is more intuitive and flexible to synchronize threads with conditions

Leave a Reply

Close Menu