Volatile boolean to prevent deadlock
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 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.