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 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