Saturday, 16 May 2015

DeadLocks and Solutions(Lock order or TryLock)

Here we are taking a banking use case. In this use case we have accounts and we want to transfer amount between accounts. End of day total need to same.


//****************************************************************
//* Copyright (c) 2015. All Rights Reserved.
//****************************************************************
package com.java.thread.deadlock;

public class Account {
    private int balance = 10000;

    public void deposit(final int amount) {
        balance += amount;
    }

    public void withdraw(final int amount) {
        balance -= amount;
    }

    public int getBalance() {
        return balance;
    }

    public static void transfer(final Account acc1, final Account acc2,
            final int amount) {
        acc1.withdraw(amount);
        acc2.deposit(amount);
    }
}
//****************************************************************
//* Copyright (c). All Rights Reserved.
//****************************************************************
package com.java.thread.deadlock;

public class DeadLockMain {
    public static void main(final String[] args) throws InterruptedException {
        final Runner runner = new Runner();

        final Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    runner.firstThread();
                } catch (final InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        final Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    runner.secondThread();
                } catch (final InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        t2.start();


        runner.finished();
    }
}

//****************************************************************
//* Copyright (c) 2015. All Rights Reserved.
//****************************************************************
package com.java.thread.deadlock;

import java.util.Random;

public class Runner {
    private Account acc1 = new Account();
    private Account acc2 = new Account();

    public void firstThread() throws InterruptedException {

        final Random random = new Random();

        for (int i = 0; i < 10000; i++) {

            Account.transfer(acc1, acc2, random.nextInt(100));
        }
    }

    public void secondThread() throws InterruptedException {
        final Random random = new Random();

        for (int i = 0; i < 10000; i++) {

            Account.transfer(acc2, acc1, random.nextInt(100));
        }
    }

    public void finished() {
        System.out.println("Account 1 balance: " + acc1.getBalance());
        System.out.println("Account 2 balance: " + acc2.getBalance());
        System.out.println("Total balance: "
                           + (acc1.getBalance() + acc2.getBalance()));
    }
}
Output:
Account 1 balance: -7122
Account 2 balance: 10517
Total balance: 3395
We need to use lock.

//****************************************************************
//* Copyright (c) 2015. All Rights Reserved.
//****************************************************************
package com.java.thread.deadlock;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Runner {
    private Account acc1 = new Account();
    private Account acc2 = new Account();

    private Lock lock1 = new ReentrantLock();
    private Lock lock2 = new ReentrantLock();

    public void firstThread() throws InterruptedException {

        final Random random = new Random();

        for (int i = 0; i < 10000; i++) {

            lock1.lock();
            lock2.lock();

            try {
                Account.transfer(acc1, acc2, random.nextInt(100));
            } finally {
                lock1.unlock();
                lock2.unlock();
            }
        }
    }

    public void secondThread() throws InterruptedException {
        final Random random = new Random();

        for (int i = 0; i < 10000; i++) {

            lock2.lock();
            lock1.lock();
            try {
                Account.transfer(acc2, acc1, random.nextInt(100));
            } finally {
                lock1.unlock();
                lock2.unlock();
            }
        }
    }

    public void finished() {
        System.out.println("Account 1 balance: " + acc1.getBalance());
        System.out.println("Account 2 balance: " + acc2.getBalance());
        System.out.println("Total balance: "
                           + (acc1.getBalance() + acc2.getBalance()));
    }
}
Above program will give you deadlock.
Solution1 Keep the order of lock object in same order in firstThread and secondThread methods.
//****************************************************************
//* Copyright (c) 2015. All Rights Reserved.
//****************************************************************
package com.java.thread.deadlock;

public class DeadLockMain {
    public static void main(final String[] args) throws InterruptedException {
        final Runner runner = new Runner();

        final Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    runner.firstThread();
                } catch (final InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        final Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    runner.secondThread();
                } catch (final InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        t2.start();



        runner.finished();
    }
}
Solution2 Use trylock

//****************************************************************
//* Copyright (c) 2015 Ford Motor Company. All Rights Reserved.
//****************************************************************
package com.java.thread.deadlock;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Runner {
    private Account acc1 = new Account();
    private Account acc2 = new Account();

    private Lock lock1 = new ReentrantLock();
    private Lock lock2 = new ReentrantLock();

    private void acquireLocks(final Lock firstLock, final Lock secondLock)
            throws InterruptedException {
        while (true) {
            // Acquire locks

            boolean gotFirstLock = false;
            boolean gotSecondLock = false;

            try {
                gotFirstLock = firstLock.tryLock();
                gotSecondLock = secondLock.tryLock();
            } finally {
                if (gotFirstLock && gotSecondLock) {
                    return;
                }

                if (gotFirstLock) {
                    firstLock.unlock();
                }

                if (gotSecondLock) {
                    secondLock.unlock();
                }
            }

            // Locks not acquired
            Thread.sleep(1);
        }
    }

    public void firstThread() throws InterruptedException {

        final Random random = new Random();

        for (int i = 0; i < 10000; i++) {

            acquireLocks(lock1, lock2);

            try {
                Account.transfer(acc1, acc2, random.nextInt(100));
            } finally {
                lock1.unlock();
                lock2.unlock();
            }
        }
    }

    public void secondThread() throws InterruptedException {
        final Random random = new Random();

        for (int i = 0; i < 10000; i++) {

            acquireLocks(lock2, lock1);
            try {
                Account.transfer(acc2, acc1, random.nextInt(100));
            } finally {
                lock2.unlock();
                lock1.unlock();
            }
        }
    }

    public void finished() {
        System.out.println("Account 1 balance: " + acc1.getBalance());
        System.out.println("Account 2 balance: " + acc2.getBalance());
        System.out.println("Total balance: "
                           + (acc1.getBalance() + acc2.getBalance()));
    }
}



//****************************************************************
//* Copyright (c) 2015. All Rights Reserved.
//****************************************************************
package com.java.thread.deadlock;

public class DeadLockMain {
    public static void main(final String[] args) throws InterruptedException {
        final Runner runner = new Runner();

        final Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    runner.firstThread();
                } catch (final InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        final Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    runner.secondThread();
                } catch (final InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        t2.start();

      
        runner.finished();
    }
}



Kindly provide your valuable feedback in comment box.

No comments:

Post a Comment