One Two Three
One Two Three

Reputation: 23517

Why does this NOT cause a dead-lock

Why does the following piece of code not cause a deadlock?

From my limited understanding of multi-threading programming, when getBar1() is called, sharedBuffer would be 'locked', hence, when the method tries to call getBar2(), the thread would have to wait for sharedBuffer (which is held by itself!). In other words, getBar2() cannot return until getBar1() has (and released sharedBuffer). But on the other hand, getBar1() cannot return either because it is waiting for getBar2() to return.

==> Deadlock. (But in actuality, it is not, which is why I am confused)

...
Foo sharedBuffer = new Foo();

Bar1 getBar1()
{
     Bar1 bar1;
     synchronized (sharedBuffer)
     {
            bar1 = sharedBuffer.getBar1();
            if (bar1 == null)
                bar1 = new Bar1(sharedBuffer, getBat2());
            sharedBuffer.setBar1(bar1);
     }
     return bar1;
}

Bar2 getBar2()
{
    Bar2 bar2;
    synchronized (sharedBuffer)
    {
        bar2 = sharedBuffer.getBar2();
        if (bar2 == null)
            bar2 = new Bar2();
    }
    return bar2;
}
...

Upvotes: 1

Views: 90

Answers (3)

atk
atk

Reputation: 9324

It doesn't deadlock because you really only have a single lock. In both functions, you're locking on sharedBuffer. When the first thread calls getBar1(), it locks on sharedBuffer. When the same thread calls getBar2(), it hits the synchronized block and already has the lock so it just enters the lock.

If you want to cause a deadlock, use two different values against which to lock. Then, you'll only see it if the timing lines up properly. If you want to force a deadlock, make sure the first thread sleeps long enough for the second thread to get a lock.

Here's some code that will deadlock... (untested, prolly has typos). This should work because a different thread has the lock than the one that wants the lock.

public class Deadlock extends Thread
{
    private Deadlock other;
    private String name;

    public static void main(String[] args)
    {
        Deadlock one = new Deadlock("one");
        Deadlock two = new Deadlock("two");
        one.setOther(two);
        two.setOther(one);
        one.start();
        two.start();
    }

    public setOther(Deadlock other){ this.other = other; }

    public void run() {
       deadlock();
    }

    public synchronized deadlock() {
         System.out.println("thread " + this.name + " entering this.deadlock()");
         sleep(1000); // adjust as needed to guarantee deadlock
         System.out.println("thread " + this.name + " calling other.deadlock()");
         other.deadlock(this.name);
         System.out.println(name + " - deadlock avoided!");
    }
}

Upvotes: 0

parsifal
parsifal

Reputation: 1266

A deadlock happens when concurrent operations attempt to lock two or more resources in a different order, and they are both stuck waiting for the resource locked by the other.

For example, threads T1 and T2 synchronize on resources R1 and R2:

  • T1 synchronizes on R1.
  • scheduler decides that T2 should run
  • T2 synchronizes on R2.
  • T2 attempts to synchronize on R1; it's forced to wait until T1 relinquishes the lock.
  • scheduler sees that T2 can't continue running, so allows T1 to run
  • T1 attempts to synchronize on R2; it's forced to wait until T2 relinquishes the lock.
  • neither thread can proceed

What you're doing here is basic synchronization, only allowing one object to access sharedBuffer at a time.

Upvotes: 0

NPE
NPE

Reputation: 500743

Java's monitors are recursive, meaning that the same thread can acquire the same locks several times.

From the JLS (§17.1 Synchronization):

A thread t may lock a particular monitor multiple times; each unlock reverses the effect of one lock operation.

Upvotes: 3

Related Questions