I have put together some Java code which demonstrates deadlock in threading. On it's own, I usually get 2 lines output and an exception, sometimes before and sometimes after the output lines which is expected. The exception I get is a NullPointerException on the first line of the transfer() method.
The problem I'm having is I'd like to know how to solve this deadlock problem. I have had a search on StackOverflow of this problem and found this page:
Avoid Deadlock example
As solutions, I have tried what Will Hartung and what Dreamcash posted but I still get exceptions when trying to use synchronize or a ReentrantLock object.
Here's the code:
Account class:
public class Account {
int id;
double balance;
public Account(int id, double balance){
this.id = id;
this.balance = balance;
}
public void withdraw(double amount){
balance = balance - amount;
}
public void deposit(double amount){
balance = balance + amount;
}
public int getID(){
return id;
}
public double getBalance(){
return balance;
}
}
Bank Class (a singleton):
public class Bank{
static Bank bank;
Account a1;
Account a2;
private Bank(){}
public static Bank getInstance(){
if(bank==null){
bank = new Bank();
bank.setAccountOne(new Account(1, 100));
bank.setAccountTwo(new Account(2, 100));
}
return bank;
}
public void transfer(Account from, Account to, double amount){
from.withdraw(amount);
to.deposit(amount);
}
public Account getAccountOne(){
return a1;
}
public Account getAccountTwo(){
return a2;
}
public void setAccountOne(Account acc){
a1 = acc;
}
public void setAccountTwo(Account acc){
a2 = acc;
}
}
PersonOne class:
public class PersonOne implements Runnable {
public void run() {
Bank bank = Bank.getInstance();
Account a1 = bank.getAccountOne();
Account a2 = bank.getAccountTwo();
bank.transfer(a2, a1, 10);
System.out.println("T1: New balance of A1 is " + a1.getBalance());
System.out.println("T1: New balance of A2 is " + a2.getBalance());
}
}
PersonTwo class:
public class PersonTwo implements Runnable {
public void run() {
Bank bank = Bank.getInstance();
Account a1 = bank.getAccountOne();
Account a2 = bank.getAccountTwo();
bank.transfer(a1, a2, 10);
System.out.println("T2: New balance of A1 is " + a1.getBalance());
System.out.println("T2: New balance of A2 is " + a2.getBalance());
}
}
And finally, my main method
public static void main(String[] args){
PersonOne p1 = new PersonOne();
PersonTwo p2 = new PersonTwo();
Thread t1 = new Thread(p1);
Thread t2 = new Thread(p2);
t1.start();
t2.start();
}
The exception I get is a NullPointerException on the first line of the transfer() method.
The problem I'm having is I'd like to know how to solve this deadlock problem.
Your code cannot possible provoke any deadlocks. What it does provoke is write visibility issues: one of the threads gets to invoke the lazy Bank initializer and the other thread does not see the write.
To get deadlocks you first need any kind of locking (the synchronized keyword). Your particular NPE problem will be solved by adding synchronized to the getInstance method and it will not introduce any deadlocks.
My conclusion is that your best recourse is reading some introductory material on concurrency in Java.
There is a number of solutions and some of the less obvious ones are
use one thread and don't use locks. In this example, the code will me much simpler and much faster with just one thread as the overhead of locks exceeds the work being done.
as this is just an example, you cold use just one global lock. This will not perform as well as multiple locks but it is much simpler and if you don't need the performance you should do the simpler , less likely to get bugs. This cannot get a deadlock.
if you have to use multiple lock because this is homework, you can ensure you always lock in the same order. You can do this by sorting the objects on a unique key and always lock the "first" item first.
lastly, you can lock the objects in any order by use tryLock on the second account. If this fails, release both locks and try again. You can perform a tryLock on a monitor using Unsafe.tryMonitor().
Thanks for your answers.
I'm currently learning about threading. In the above, I was purposefully trying to create a deadlock, so that I could learn how to solve the problem of deadlocks (if I actually wanted a program that did the above, I would just avoid multi-threading).
The reason I used a singleton was so the two threads would be trying to use the same objects.
So... the above was the code I used to try to recreate a deadlock, so I was expecting problems/exceptions when running. One way I tried to then fix it was by rewriting the transfer method to look like this:
public void transfer(Account from, Account to, double amount){
synchronized(from){
synchronized(to){
from.withdraw(amount);
to.withdraw(amount);
}
}
}
But I'd get a NullPointerException on the synchronized(from) line.
I also tried this in the transfer method (and account had a ReentrantLock object inside it). But this time I'd get a NullPointerException on the line that reads from.getLock().unlock()
public void transfer(Account from, Account to, double amount){
while(true){
try{
if(from.getLock().tryLock()){
try{
if(to.getLock().tryLock()){
from.withdraw(amount);
to.withdraw(amount);
break;
}
} finally {
to.getLock().unlock();
}
}
} finally{
from.getLock().unlock();
}
Random random = new Random();
int i = random.nextInt(1000);
try {
Thread.sleep(1000 + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Related
I have written a demo code for Atm machine while using synchronization
class Atm{
synchronized void checkBalance(String str){
System.out.print(str+" is checking his ");
try{Thread.sleep(1000);}catch(Exception e){
System.out.println(e);
}
System.out.println("Balance ");
}
synchronized void withdraw(String str, int amt){
System.out.print(str+ " is withdrawing amount: ");
try{Thread.sleep(1000);}catch(Exception e){
System.out.println(e);
}
System.out.println(amt);
}
}
class Customer extends Thread{
String name;
int amt;
Atm a;
Customer (Atm a){
this.a=a;
}
public void useAtm(){
a.checkBalance(name);
a.withdraw(name,amt);
}
public void run(){
useAtm();
}
}
after running the main method i get the output as Output where as soon as the thread 1 after releasing checkBalance, goes to withdraw method but thread 2 gets access to check balance before thread 1 could get monitor on withdraw and i get the output as such.
But on other cases i get the output as: Output 2 in order... where the threads access the methods one after another. How can i make sure that thread 2 or any other thread doesn't access checkBalance till thread 1 has completed accessing both checkBalance and withdraw?
Basically how to make the output as "Ram checks, Ram withdraws, S checks, S withdraws...." instead of "R checks, S checks, S withdraws, R withdraws"
Main:
public class Main {
public static void main(String[] args) {
// write your code here
Atm a=new Atm();
Customer c1=new Customer(a);
Customer c2=new Customer(a);
Customer c3=new Customer(a);
c1.name="Ram";
c1.amt=5000;
c2.name="Hari";
c2.amt=51000;
c3.name="Shyam";
c3.amt=545000;
Customer c4=new Customer(a);
Customer c5=new Customer(a);
Customer c6=new Customer(a);
c4.name="xam";
c4.amt=500220;
c5.name="pari";
c5.amt=5100220;
c6.name="ohyam";
c6.amt=54501200;
c1.start();
c2.start();
c3.start();
c4.start();
c5.start();
c6.start();
}
}
Here you did try to synchronize functions individually, which make sense if you want to use them separately synchronized. But when you want two functions to run in a synchronized way try using
public void useAtm(){
synchronized(a){
a.checkBalance(name);
a.withdraw(name,amt);
}
}
which will solve your problem. Try removing synchronized tag to methods.
void checkBalance(String str){
void withdraw(String str, int amt){
I hope it solved your issue.
I have two classes that extends Thread. Class One, and class Two.
In my driver class, I create three threads of class One, and one hundred threads of class Two.
Each class One thread needs to notify every class Two thread that it's available to interact. After the two threads interact, the thread One moves on to another class Two thread that hasn't had an interaction with a class One thread.
How do I connect the two types of threads? How do I connect class 1 and class 2 threads. How does a thread using class 1 let every thread using class 2 know that it is available for interaction?
ex code:
public class Driver {
public static Semaphore sem = new Semaphore(1);
public static void main(String[] args) {
// TODO Auto-generated method stub
Teller tellerOne = new Teller(1);
Teller tellerTwo = new Teller(2);
Teller tellerThree = new Teller(3);
tellerOne.start();
tellerTwo.start();
tellerThree.start();
Client[] clients = new Client[10];
for(int i = 0; i<10; i++){
clients[i] = new Client(i);
clients[i].start();
}
System.out.println("Bank closes");
//end main method. do not write past this line
}
public class Teller extends Thread {
public int id;
public boolean bankOpen;
public Semaphore tsem;
Teller(int id){
this.id = id;
}
public void run(){
System.out.println("Teller " + id + " is available");
//end of run
}
//method to notify availability to client
public void notifyAvailabilityToClient(){
}
//end teller class, do not write past this line
public class Client extends Thread {
public int id;
public String status;
public Semaphore csem;
Client(int id){
this.id = id;
}
public void run(){
Random rand = new Random();
int withdrawOrDeposit = rand.nextInt(100);
withdrawOrDeposit = withdrawOrDeposit%2;
//if wORd%2 = 0, withdraw, else deposit
if(withdrawOrDeposit==0){
status="Withdraw";
}
else{
status="Deposit";
}
System.out.println("Client " + id + " waits in line to make a " + status);
//end of run method, do not write past this
}
//method to select an open Teller
public void selectAvailableTeller(){
}
//end of client class, do not write past this line
Btw I can use classes: Semaphore and Threads
I would not normally write code in which different threads meet up with each other, but since this appears to be a homework assignment...
In my solution there would be a single, blocking queue. When a "teller" thread starts up, and each time it finishes "interacting" with a customer, it would put its self into the queue, and then wait for a new customer to start an interaction. The customers all would wait to take() a teller from the queue, and when they get one,... "interact" with it.
If it was not homework I would do something entirely different. I don't know why "customer" threads are a thing, but I don't see any use for "teller" threads at all. There might be some kind of limited-availability Teller objects, but they would not be threads. The customer threads could "interact" by simply calling Teller methods or, if necessary, by submitting tasks that call Teller methods to a generic thread pool.
I was looking for deadlock example and stumbled across this code:
package com.example.thread.deadlock._synchronized;
public class BankAccount {
double balance;
int id;
BankAccount(int id, double balance) {
this.id = id;
this.balance = balance;
}
void withdraw(double amount) {
// Wait to simulate io like database access ...
try {Thread.sleep(10l);} catch (InterruptedException e) {}
balance -= amount;
}
void deposit(double amount) {
// Wait to simulate io like database access ...
try {Thread.sleep(10l);} catch (InterruptedException e) {}
balance += amount;
}
static void transfer(BankAccount from, BankAccount to, double amount) {
synchronized(from) {
from.withdraw(amount);
synchronized(to) {
to.deposit(amount);
}
}
}
public static void main(String[] args) {
final BankAccount fooAccount = new BankAccount(1, 100d);
final BankAccount barAccount = new BankAccount(2, 100d);
new Thread() {
public void run() {
BankAccount.transfer(fooAccount, barAccount, 10d);
}
}.start();
new Thread() {
public void run() {
BankAccount.transfer(barAccount, fooAccount, 10d);
}
}.start();
}
}
How would you change transfer method so that it doesn't cause deadlock? First thought is to create a shared lock for all accounts, but that of course would just kill all concurrency. So is there a good way to lock just two accounts involved into a transaction and not affect other accounts?
One way to avoid deadlocks in multi-lock situations is to always lock the objects in the same order.
In this case it would mean that you'd create a total ordering for all BankAccount objects. Luckily we've got an id that we can use, so you could always lock the lower id first and then (inside the other synchronized block) the higher id one.
This assumes that there's no BankAccount objects with identical ids, but that seems like a reasonable assumption.
Use two synchronized blocks separately instead of nested.
synchronized(from){
from.withdraw(amount);
}
synchronized(to){
to.deposit(amount);
}
So after from.withdraw(amount) is called, the lock on from is released before it tries to lock on to
public class Test implements Runnable{
private String name;
public Test(String name){
this.name = name;
}
public void run() {
blah(name);
}
public synchronized void blah(String obj) {
System.out.println("Here: "+obj);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Test x = new Test("X");
Test y = new Test("Y");
Thread tx = new Thread(x);
Thread ty = new Thread(y);
tx.start();
ty.start();
}
This example should help me to understand synchronization, but I don't. This is because if I remove the word synchronize, it printed the same output (random)
Synchronization is irrelevant here because your two threads are each synchronizing on their own Runnable. There is no shared lock, and no shared data.
If you pass the same Runnable instance into each Thread then they will share the same lock. If your Runnable does something in a thread-unsafe way (like using ++ to increment a shared variable (an instance variable of the Runnable), or adding the entry to a shared ArrayList) then you can create a situation where removing synchronization can make the code break (with the understanding that breakage may not happen reliably, that's what makes multithreaded programming fun).
Making toy examples like this is not a good preparation for real-life multithreading. Threads shouldn't be in the business of implementing locking, they should be accessing data objects that enforce their own invariants.
Your example is technically correct, but there is no timing dependent conflict in your synchronized block. As such, there is no chance that you will see different output, regardless of the ordering of the calls.
In addition, you create two resources, and there is no cross-thread communication between the two resources, so effectively you've tested two synchronized blocks once each.
You need an example that can break when not synchronized.
Here is an example that can break
public class Counter {
int count;
public Counter() {
count = 0;
}
public int getCount() {
return count;
}
public /* need synchronized here */ void update(int value) {
int buffer = 0;
buffer = buffer + count;
buffer = buffer + value;
count = buffer;
}
}
public class UpdateCounter extends Thread {
public UpdateCounter(Counter counter, int amount) {
this.counter = counter;
this.name = name;
}
public void run() {
System.out.printf("Adding %d to count\n", amount);
counter.update(amount);
System.out.printf("Count is %d\n", counter.getCount());
}
}
public static void main(String[] args) {
Counter counter = new Counter();
UpdateCounter x = new UpdateCounter(counter, 30);
UpdateCounter y = new UpdateCounter(counter, 100);
x.start();
y.start();
}
With an example like this, one would eventually see a series of lines that indicated some value was being added to the counter, but the counter would update by the wrong value.
This is because one thread will eventually get paused with a buffer holding the "next" value, and the other thread will race across the same block of code, storing its "next" value into count. Then the paused thread will un-pause, and store its "next" value effectively removing the amount added by the thread that raced ahead of it.
By adding the synchronized keyword, only one thread is allowed entry into the update block, and the race condition I described above cannot occur.
Note that this is an example that can fail with bad synchronization, and not a good way to implement a counter.
I am wondering what are the alternative ways to avoid deadlock in the following example. The following example is a typical bank account transferring deadlock problem. What are some of the better approaches to solve it in practice ?
class Account {
double balance;
int id;
public Account(int id, double balance){
this.balance = balance;
this.id = id;
}
void withdraw(double amount){
balance -= amount;
}
void deposit(double amount){
balance += amount;
}
}
class Main{
public static void main(String [] args){
final Account a = new Account(1,1000);
final Account b = new Account(2,300);
Thread a = new Thread(){
public void run(){
transfer(a,b,200);
}
};
Thread b = new Thread(){
public void run(){
transfer(b,a,300);
}
};
a.start();
b.start();
}
public static void transfer(Account from, Account to, double amount){
synchronized(from){
synchronized(to){
from.withdraw(amount);
to.deposit(amount);
}
}
}
}
I am wondering if the deadlock issue will be solved if I separate the nested lock out in my transfer method like the following
synchronized(from){
from.withdraw(amount);
}
synchronized(to){
to.deposit(amount);
}
Sort the accounts. The dead lock is from the ordering of the accounts (a,b vs b,a).
So try:
public static void transfer(Account from, Account to, double amount){
Account first = from;
Account second = to;
if (first.compareTo(second) < 0) {
// Swap them
first = to;
second = from;
}
synchronized(first){
synchronized(second){
from.withdraw(amount);
to.deposit(amount);
}
}
}
In addition to the solution of lock ordered you can also avoid the deadlock by synchronizing on a private static final lock object before performing any account transfers.
class Account{
double balance;
int id;
private static final Object lock = new Object();
....
public static void transfer(Account from, Account to, double amount){
synchronized(lock)
{
from.withdraw(amount);
to.deposit(amount);
}
}
This solution has the problem that a private static lock restricts the system to performing transfers "sequentially".
Another one can be if each Account has a ReentrantLock:
private final Lock lock = new ReentrantLock();
public static void transfer(Account from, Account to, double amount)
{
while(true)
{
if(from.lock.tryLock()){
try {
if (to.lock.tryLock()){
try{
from.withdraw(amount);
to.deposit(amount);
break;
}
finally {
to.lock.unlock();
}
}
}
finally {
from.lock.unlock();
}
int n = number.nextInt(1000);
int TIME = 1000 + n; // 1 second + random delay to prevent livelock
Thread.sleep(TIME);
}
}
Deadlock does not occur in this approach because those locks will never be held indefinitely. If the current object's lock is acquired but the second lock is unavailable, the first lock is released and the thread sleeps for some specified amount of time before attempting to reacquire the lock.
This is a classic question. I see two possible solutions:
To sort accounts and synchronize at account which has an id lower than another one.
This method mentioned in the bible of concurrency Java Concurrency in Practice in chapter 10. In this book authors use system hash code to distinguish the accounts. See java.lang.System#identityHashCode.
The second solution is mentioned by you - yes you can avoid nested synchronized blocks and your code will not lead to deadlock. But in that case the processing might have some problems because if you withdraw money from the first account the second account may be locked for any significant time and probably you will need to put money back to the first account. That's not good and because that nested synchronization and the lock of two accounts is better and more commonly used solution.
You can also create separate lock for each Account (in Account class) and then before doing transaction acquire both locks. Take a look:
private boolean acquireLocks(Account anotherAccount) {
boolean fromAccountLock = false;
boolean toAccountLock = false;
try {
fromAccountLock = getLock().tryLock();
toAccountLock = anotherAccount.getLock().tryLock();
} finally {
if (!(fromAccountLock && toAccountLock)) {
if (fromAccountLock) {
getLock().unlock();
}
if (toAccountLock) {
anotherAccount.getLock().unlock();
}
}
}
return fromAccountLock && toAccountLock;
}
After get two locks you can do transfer without worrying about safe.
public static void transfer(Acc from, Acc to, double amount) {
if (from.acquireLocks(to)) {
try {
from.withdraw(amount);
to.deposit(amount);
} finally {
from.getLock().unlock();
to.getLock().unlock();
}
} else {
System.out.println(threadName + " cant get Lock, try again!");
// sleep here for random amount of time and try do it again
transfer(from, to, amount);
}
}
Here is the solution for the problem stated.
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FixDeadLock1 {
private class Account {
private final Lock lock = new ReentrantLock();
#SuppressWarnings("unused")
double balance;
#SuppressWarnings("unused")
int id;
public Account(int id, double balance) {
this.balance = balance;
this.id = id;
}
void withdraw(double amount) {
this.balance -= amount;
}
void deposit(double amount) {
balance += amount;
}
}
private class Transfer {
void transfer(Account fromAccount, Account toAccount, double amount) {
/*
* synchronized (fromAccount) { synchronized (toAccount) {
* fromAccount.withdraw(amount); toAccount.deposit(amount); } }
*/
if (impendingTransaction(fromAccount, toAccount)) {
try {
System.out.format("Transaction Begins from:%d to:%d\n",
fromAccount.id, toAccount.id);
fromAccount.withdraw(amount);
toAccount.deposit(amount);
} finally {
fromAccount.lock.unlock();
toAccount.lock.unlock();
}
} else {
System.out.println("Unable to begin transaction");
}
}
boolean impendingTransaction(Account fromAccount, Account toAccount) {
Boolean fromAccountLock = false;
Boolean toAccountLock = false;
try {
fromAccountLock = fromAccount.lock.tryLock();
toAccountLock = toAccount.lock.tryLock();
} finally {
if (!(fromAccountLock && toAccountLock)) {
if (fromAccountLock) {
fromAccount.lock.unlock();
}
if (toAccountLock) {
toAccount.lock.unlock();
}
}
}
return fromAccountLock && toAccountLock;
}
}
private class WrapperTransfer implements Runnable {
private Account fromAccount;
private Account toAccount;
private double amount;
public WrapperTransfer(Account fromAccount,Account toAccount,double amount){
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.amount = amount;
}
public void run(){
Random random = new Random();
try {
int n = random.nextInt(1000);
int TIME = 1000 + n; // 1 second + random delay to prevent livelock
Thread.sleep(TIME);
} catch (InterruptedException e) {}
new Transfer().transfer(fromAccount, toAccount, amount);
}
}
public void initiateDeadLockTransfer() {
Account from = new Account(1, 1000);
Account to = new Account(2, 300);
new Thread(new WrapperTransfer(from,to,200)).start();
new Thread(new WrapperTransfer(to,from,300)).start();
}
public static void main(String[] args) {
new FixDeadLock1().initiateDeadLockTransfer();
}
}
There are three requirements you must satisfy:
Consistently reduce the contents of one account by the specified amount.
Consistently increase the contents of the other account by the specified amount.
If one of the above is successful, the other must also be successful.
You can achieve 1. and 2. by using Atomics, but you will have to use something other that double as there is no AtomicDouble. AtomicLong would probably be your best bet.
So you're left with your third requirement - if one succeeds the other must succeed. There is a simple technique that works superbly with atomics and that is using the getAndAdd methods.
class Account {
AtomicLong balance = new AtomicLong ();
}
...
Long oldDebtor = null;
Long oldCreditor = null;
try {
// Increase one.
oldDebtor = debtor.balance.getAndAdd(value);
// Decrease the other.
oldCreditor = creditor.balance.gtAndAdd(-value);
} catch (Exception e) {
// Most likely (but still incredibly unlikely) InterruptedException but theoretically anything.
// Roll back
if ( oldDebtor != null ) {
debtor.getAndAdd(-value);
}
if ( oldCreditor != null ) {
creditor.getAndAdd(value);
}
// Re-throw after cleanup.
throw (e);
}