Is it possible for a thread to Deadlock itself?

Viewed 14020

Is it technically possible for a thread in Java to deadlock itself?

I was asked this at an interview a while back and responded that it wasn't possible but the interviewer told me that it is. Unfortunately I wasn't able to get his method on how to achieve this deadlock.

This got me thinking and the only situation that I can think of is where you can have this happen is where you have an RMI server process which contained a method that calls itself. The line of code that calls the method is placed in a synchronized block.

Is that even possible or was the interviewer incorrect?

The source code I was thinking about was along these lines (where testDeadlock is running in an RMI server process)

public boolean testDeadlock () throws RemoteException {
    synchronized (this) {
        //Call testDeadlock via RMI loopback            
    }
}
20 Answers

A deadlock is a form of resource starvation with an interaction between multiple threads.

When a thread gets into a state of resource staving itself, it is referred to a livelock which is similar to a deadlock, but not the same by definition.

An example of a livelock is using ReentrantReadWriteLock. Despite being reentrant on reading OR writing, it doesn't allow upgrading the lock from read to write.

public class LiveLock {
    public static void main(String[] args) {
        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        lock.readLock().lock();
        if (someCondition()) {
            // we want to write without allowing another thread to jump in.
            lock.writeLock().lock();
        }
    }

    private static boolean someCondition() {
        return true;
    }
}

results in the process blocking here

"main" #1 prio=5 os_prio=0 tid=0x0000000002a52800 nid=0x550c waiting on condition [0x000000000291f000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007162e5e40> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
    at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:943)
    at LiveLock.main(LiveLock.java:10)

A related question is; can a thread get into a deadlock without creating additional threads. This is possible as there are background threads e.g. the finalizer thread, which can run user code in the background. This allows for the main thread and the finalizer thread to deadlock each other.

The answer (Pram's) marked as correct isn't technically a deadlock as others have suggested. Its just blocked.

I would suggest in Java, you can lean on Java's definition (which is consistent with the two thread idea). The ultimate judge then can be the JVM if it detects the deadlock itself. So, in Pram's example, the thread would show something like the following if it was a geniune deadlock.

Deadlock detected
=================

"Negotiator-Thread-1":
  waiting to lock Monitor of com.google.code.tempusfugit.concurrency.DeadlockDetectorTest$Cat@ce4a8a
  which is held by "Kidnapper-Thread-0"

"Kidnapper-Thread-0":
  waiting to lock Monitor of com.google.code.tempusfugit.concurrency.DeadlockDetectorTest$Cash@7fc8b2
  which is held by "Negotiator-Thread-1"

This deadlock detection has been available for intrinsic locks since 1.5 and Lock based cyclic deadlocks since 1.6.

A continuously blocked resource, or at least something that is waiting for something that will never happen is called a livelock. Similar problems where processes outside the VM (for example) databases deadlocking are entirely possible but I'd argue not appropriate for the question.

I'd be interested in a write up of how the interviewer claims its possible...

In answer to your original question, it takes two to tango and I'd suggest Pram's answer shouldn't be marked as correct because its not! ;) The RMI thread which calls back can cause blocking but it runs on a different thread (managed by the RMI server) than that of main. Two threads are involved even if the main thread didn't explicitly set another one up. There is no deadlock as witnessed by the lack of the detection in the thread dump (or if you click 'detect deadlock' in jconsole), it'd be more accurately described as a livelock.

Having said all that, any discussion along the lines of each of these answers would be enough to satisfy me as an interviewer.

Although the comments here are being pedantic about "deadlock" happening if at least two threads/actions are competing for the same resource...I think the spirit of this question was to discuss a need for Reentrant lock - especially in context of "recursive" locking

Here's an example in python (I am certain the concept stays the same in Java): If you change the RLock to Lock (i.e. reentrant lock to lock, the thread will hang)

import threading

"""
Change RLock to Lock to make it "hang"
"""
lock = threading.Condition(threading.RLock())


def print_list(list):
    lock.acquire()
    if not list:
        lock.release()
        return
    print(list[0])
    print_list(list[1:])
    lock.release()


print_list([1, 2, 3, 4, 5])
Related