patternjavaMinor
Volatile boolean to prevent deadlock
Viewed 0 times
deadlockpreventvolatileboolean
Problem
I wrote this code to overcome the deadlock condition described in this Oracle tutorial.
Summary of Problem:
Alphonse and Gary are friends, and great believers in courtesy. A strict rule of courtesy is that when you bow to a friend, you must remain bowed until your friend has a chance to return the bow. Unfortunately, this rule does not account for the possibility that two friends might bow to each other at the same time.
I used a volatile boolean
Is this a valid way to handle deadlocks as opposed to using locks?
```
public class NewThread extends Thread {
Friend bower;
Friend bowBack;
NewThread(Friend bower,Friend bowBack){
this.bower = bower;
this.bowBack = bowBack;
}
@Override
public void run(){
if(bowBack.canBow())
bower.bow(bowBack);
}
}
public class ApplicationThread {
public static void main(String[] args) {
final Friend alphonse = new Friend("Alphonse");
final Friend gary = new Friend("Gary");
NewThread t1 = new NewThread(alphonse,gary);
NewThread t2 = new NewThread(gary,alphonse);
t1.start();
t2.start();
}
static class Friend {
private final String name;
private volatile boolean canBow;
public Friend(String name) {
this.name = name;
canBow = true;
}
public String getName() {
return this.name;
}
public boolean canBow(){
return canBow;
}
public synchronized void bow(Friend bower) {
canBow = false;
System.out.format("%s: %s"
+ " has bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
canBow = true;
}
public synchronized void bow
Summary of Problem:
Alphonse and Gary are friends, and great believers in courtesy. A strict rule of courtesy is that when you bow to a friend, you must remain bowed until your friend has a chance to return the bow. Unfortunately, this rule does not account for the possibility that two friends might bow to each other at the same time.
I used a volatile boolean
CanBow() to check if either of the friends are bowing so that the condition when both of them bow and wait for the other to bow back will not happen.Is this a valid way to handle deadlocks as opposed to using locks?
```
public class NewThread extends Thread {
Friend bower;
Friend bowBack;
NewThread(Friend bower,Friend bowBack){
this.bower = bower;
this.bowBack = bowBack;
}
@Override
public void run(){
if(bowBack.canBow())
bower.bow(bowBack);
}
}
public class ApplicationThread {
public static void main(String[] args) {
final Friend alphonse = new Friend("Alphonse");
final Friend gary = new Friend("Gary");
NewThread t1 = new NewThread(alphonse,gary);
NewThread t2 = new NewThread(gary,alphonse);
t1.start();
t2.start();
}
static class Friend {
private final String name;
private volatile boolean canBow;
public Friend(String name) {
this.name = name;
canBow = true;
}
public String getName() {
return this.name;
}
public boolean canBow(){
return canBow;
}
public synchronized void bow(Friend bower) {
canBow = false;
System.out.format("%s: %s"
+ " has bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
canBow = true;
}
public synchronized void bow
Solution
Welcome to the wonderful world of deadlocks. In a nutshell: No, your “solution” is not adequate. Here is some pseudocode detailing what the two threads are doing. Note that a
We can see that
You can make this deadlock more likely by increasing the time between the
To solve these issues, you could impose an order or hierarchy on the friends, so that locks are aquired in exactly the same order in all threads (e.g. always synchronize on
But your implementation doesn't work.
synchronized method aquires a lock on the object it is called on.THREAD 1 | THREAD 2
IF: | IF:
synchronized (gary) { | synchronized (alphonse) {
// gary.canBow(); | // alphonse.canBow();
gary.canBow; | alphonse.canBow;
} | }
THEN: | THEN:
synchronized (alphonse) { | synchronized (gary) {
// alphonse.bow(gary); | // gary.bow(alphonse);
alphonse.canBow = false; | gary.canBow = false;
... | ...
// gary.bowBack(alphonse) | // alphonse.bowBack(gary)
synchronized (gary) { | synchronized (alphonse) {
... | ...
} | }
alphonse.canBow = true; | gary.canBow = true;
} | }We can see that
gary and alphonse can be locked at the same time. Especially, the bowBack.canBow() can return true in both threads. Then, even when the canBow boolean is volatile, both objects can wait for each other in a deadlock (in Thread 1, alphonse is locked and waits for gary. In Thread 2, the other way round).You can make this deadlock more likely by increasing the time between the
bowBack.canBow() and bower.bow() calls:public void run(){
if(bowBack.canBow()) {
Thread.sleep(100); // exception handling omitted
bower.bow(bowBack);
}
}To solve these issues, you could impose an order or hierarchy on the friends, so that locks are aquired in exactly the same order in all threads (e.g. always synchronize on
alphonse before gary). You could also decide that only one friend may initiate a bow at any time, e.g. via a semaphore.But your implementation doesn't work.
Code Snippets
THREAD 1 | THREAD 2
IF: | IF:
synchronized (gary) { | synchronized (alphonse) {
// gary.canBow(); | // alphonse.canBow();
gary.canBow; | alphonse.canBow;
} | }
THEN: | THEN:
synchronized (alphonse) { | synchronized (gary) {
// alphonse.bow(gary); | // gary.bow(alphonse);
alphonse.canBow = false; | gary.canBow = false;
... | ...
// gary.bowBack(alphonse) | // alphonse.bowBack(gary)
synchronized (gary) { | synchronized (alphonse) {
... | ...
} | }
alphonse.canBow = true; | gary.canBow = true;
} | }public void run(){
if(bowBack.canBow()) {
Thread.sleep(100); // exception handling omitted
bower.bow(bowBack);
}
}Context
StackExchange Code Review Q#29892, answer score: 6
Revisions (0)
No revisions yet.