Reputation: 193
Below code I have written for a deadlock, but for small "for loop" code is not falling in deadlock while when I keep "for loop" till 10 then deadlock is occurring.
Can someone plz explain, why it is showing such behavior ?
public class CustomerUpdateDeadloackThread {
public static void main(String[] args) {
Customer cstmr = new Customer("Peter");
Address adrs = new Address("B-232, Bangalore");
// For loop till 3 is not showing deadlock.
for (int i=0; i<10;i++){
new Thread(new TagObjectsToEachOther(cstmr, adrs)).start();
new Thread(new TagObjectsToEachOther(adrs, cstmr)).start();
}
}
}
interface CustomerUpdater {
public boolean update(Object obj);
}
class TagObjectsToEachOther implements Runnable {
CustomerUpdater taskItem;
Object objToUpdateWith;
public TagObjectsToEachOther(CustomerUpdater cspdtr, Object obj2) {
this.taskItem = cspdtr;
this.objToUpdateWith = obj2;
}
@Override
public void run() {
taskItem.update(objToUpdateWith);
System.out.println(" Task done :" + Thread.currentThread().getName());
}
}
class Address implements CustomerUpdater {
String address;
Customer customer;
public Address(String addrs) {
this.address = addrs;
}
@Override
public boolean update(Object cstmr) {
synchronized (this) {
synchronized ((Customer) cstmr) {
try {
this.customer = (Customer) cstmr;
Thread.sleep(2000); // or else do some other work here
} catch (CustomerUpdateFailureException e) {
e.getCause();
return false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
}
}
}
class Customer implements CustomerUpdater {
String name;
Address address;
public Customer(String nm) {
this.name = nm;
}
@Override
public boolean update(Object adrs) {
synchronized (this) {
synchronized ((Address) adrs) {
try {
this.address = (Address) adrs;
Thread.sleep(2000); // or else do some other work here
} catch (CustomerUpdateFailureException e) {
e.getCause();
return false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
}
}
}
class CustomerUpdateFailureException extends RuntimeException {
private static final long serialVersionUID = 1L;
@Override
public String getMessage() {
return "Uncompitable update";
}
}
Upvotes: 2
Views: 265
Reputation: 1499770
You're only going to get a deadlock if one of your threads obtains one monitor and the other thread obtains the other monitor before the first thread obtains the second monitor. The more threads you have obtaining the monitors on the two objects, the more likely it is that one of them will obtain just one lock and be pre-empted before it gets a chance to obtain the second monitor.
In other words, this is fine, and just causes a wait:
Thread A Thread B
Lock X
Lock Y
Lock Y // Blocks (temporary)
Sleep
Lock X
Sleep
Whereas this causes deadlock:
Thread A Thread B
Lock X
Lock Y
Lock Y // Blocks (deadlock)
Lock X // Blocks (deadlock)
If you move your Thread.sleep(2000)
call to between your two synchronized
statements (in both methods) then you're almost guaranteed to get a deadlock, without any looping at the top level.
Upvotes: 6