16
    public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s"
                + "  has bowed to me!%n", 
                this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s"
                + " has bowed back to me!%n",
                this.name, bower.getName());
        }
    }

    public static void main(String[] args) {
        final Friend alphonse =
            new Friend("Alphonse");
        final Friend gaston =
            new Friend("Gaston");
        new Thread(new Runnable() {
            public void run() { alphonse.bow(gaston); }
        }).start();
        new Thread(new Runnable() {
            public void run() { gaston.bow(alphonse); }
        }).start();
    }
}

when i run this program i am getting the output as

Alphonse: Gaston has bowed to me! Gaston: Alphonse has bowed to me!

So can two threads access a synchronized method at the same time?

harish
  • 328
  • 2
  • 5
  • 14
  • possible duplicate of [Trying to wrap my wee brain around how threads deadlock](http://stackoverflow.com/questions/749641/trying-to-wrap-my-wee-brain-around-how-threads-deadlock) – Oleg Estekhin Jul 09 '14 at 12:34

5 Answers5

15

Can two threads access a synchronized method at the same time?

It depends on what object instance the two threads are trying to lock on. Two threads cannot access the same synchronized method on the same object instance. One will get the lock and the other will block until the first thread leaves the method.

In your example, instance methods are synchronized on the object that contains them. In this case, when you call alphonse.bow(...) you are locking on the alphonse object. gaston.bow(...) locks gaston.

There are a couple of ways that you can get multiple instances of an object to lock on the same object.

  • You could make the method be static and synchronized in which case they would lock on the class object itself. There is only one of these objects per class loader.

    public static synchronized void bow(Friend bower) {
    
  • They could both lock on a defined static object. Something like:

    private static final Object lockObject = new Object();
    ...
    public void bow(Friend bower) {
        synchronized (lockObject) {
            ....
        }
    }
    
  • Or you could could pass in the object to lock on if you didn't want to make it static.

Your output could be something like the following:

  1. the gaston thread (may) start first and calls bow(alphonse)
  2. this locks the gaston object and outputs: Gaston: Alphonse has bowed to me!
  3. it calls alphonse.bowBack(this).
  4. this call locks the alphonse object and outputs: Alphonse: Gaston has bowed back to me!
  5. alphonse.bowBack(this) exits, unlocking the alphonse object.
  6. gaston.bow(alphonse) exits, unlocking the gaston object.
  7. then the gaston thread exits.
  8. the alphonse thread (may) start next and calls bow(gaston)
  9. this locks the alphonse object and outputs: Alphonse: Gaston has bowed to me!
  10. it calls gaston.bowBack(this).
  11. this call locks the gaston object and outputs: Gaston: Alphonse has bowed back to me!
  12. gaston.bowBack(this) exits, unlocking the gaston object.
  13. alphonse.bow(gaston) exits, unlocking the alphonse object.

This could happen in a number of different orders. The alphonse thread could run first even though it's start() method gets called at a later time. The only thing that the locks save you from is the calling of alphonse.bow(...) if alphonse.bowBack(...) is currently running. As @user988052 pointed out, because each thread locks their own object and then tries to lock the other, you can easily get a deadlock.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • ok..but sometimes when i run this program i get the output as: Gaston: Alphonse has bowed to me! Alphonse: Gaston has bowed back to me! Alphonse: Gaston has bowed to me! Gaston: Alphonse has bowed back to me! So..how that happens..i mean this program is supposed to block as in the tutorial.. – harish Feb 21 '12 at 17:47
  • @harish: it happens because the first thread may have finished its work before the second thread has started. Which is why to create for sure (well, at least with a very probability) a deadlock, you have to instantiate lots of threads (see my answer). – TacticalCoder Feb 21 '12 at 17:54
14

So can two threads access a synchronized method at the same time?

Yes and no:

  • Yes, if the method is called on different instances of the class.

  • No, two threads can't simultaneously call synchronized methods on the same instance of the class. This is the case even if the two threads call different methods (as long as the instance is the same).

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 2
    Note: if a synchronized method calls another synchronized method on the same object, then one thread can be in two synchronized methods on the same object at once. – Louis Wasserman Feb 21 '12 at 17:27
  • @aix - can you modify your answer to indicate that the synchronization is being done on the class. Also your first bullet point is not correct for class synchronization. – Perception Feb 21 '12 at 17:35
  • @Perception: Not sure I follow. Since the methods are not `static`, synchronization locks the instance, not the class. Could you explain what you mean? – NPE Feb 21 '12 at 17:37
  • @aix - Never mind. I would have sworn they were static but I guess I misread. – Perception Feb 21 '12 at 17:48
2

I didn't check your code in detail but I think I recognize the typical example as to how to create a deadlock.

However you shouldn't call it just once to try to create the deadlock.

Create threads in a loop and there's a very high probability you'll get your deadlock:

for ( int i = 0; i < 1000; i++ ) {
    final Friend alphonse =
        new Friend("Alphonse");
    final Friend gaston =
        new Friend("Gaston");
    new Thread(new Runnable() {
        public void run() { alphonse.bow(gaston); }
    }).start();
    new Thread(new Runnable() {
        public void run() { gaston.bow(alphonse); }
    }).start();
}

Note that you won't deadlock your 2000 threads: only some of them will be deadlocked. You can verify this by taking a threadump of your program/JVM.

TacticalCoder
  • 6,275
  • 3
  • 31
  • 39
1

With the synchronized keyword you take a lock on an instance for an instance method or on a class for a static method. So here you guarantee that at most one thread executes bow or bowBack on a given instance at a given time (if one thread executes bow no other thread can execute bowBack because both methods synchronize on the same lock)...

One more comment: as locks are reentrant once a thread has acquired a lock it can enter other methods synchronizing on the same lock.

pgras
  • 12,614
  • 4
  • 38
  • 46
1

As described in the Deadlock Tutorials which is where this code comes from this code will usually block.

When Deadlock runs, it's extremely likely that both threads will block when they attempt to invoke bowBack. Neither block will ever end, because each thread is waiting for the other to exit bow.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213