Is it possible for a thread to Deadlock itself?

JavaMultithreadingDeadlockRmi

Java Problem Overview


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			
	}
}

Java Solutions


Solution 1 - Java

Well, based on the definition of:

> A deadlock is a situation wherein two or more competing actions are each waiting for the other to finish.

I would say that the answer is no - sure a thread can sit there waiting indefinitely for something, however unless two competing actions are waiting for each other it is by definition not a deadlock.

Unless someone explains to me how a single thread can be simultaneously waiting for two actions to finish?

UPDATE: The only possible situation that I can think of is some sort of message pump, where a thread processes a message that asks it to wait indefinitely for something to happen, where in fact that something will be processed by another message on the message pump.

This (incredibly contrived) scenario could possibly be technically called a deadlock.

Solution 2 - Java

It depends on what you mean by "deadlock" exactly. For example, you could easily wait() on a monitor which nothing would ever pulse... but I don't think I'd call that deadlock, as such.

Thinking along your "method that calls itself" lines, if your server only ran a certain number of threads, they could all be busy waiting from responses from the same server, if that counts. (Simplest example: the server only uses one thread for processing. If you write a request handler which calls into the same server, it will be waiting for the blocked thread to finish handling the request before it can serve the same request...) This isn't really a "synchronized block" sort of deadlock, but it's certainly a danger to be aware of.

EDIT: To apply this answer to the definition in the others, the competing actions here would be "complete the current request" and "handle the new request". Each action is waiting for the other to occur.

Solution 3 - Java

Maybe he meant LOCK itself, that's certainly too easy:

synchronized( this )
{
    wait( );
}

Solution 4 - Java

Maybe what the interviewer was thinking of was:

Thread.currentThread().join();

However I would argue that it does not count as a deadlock.

Solution 5 - Java

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.

Solution 6 - Java

Upgrading from a read lock to a write lock (trying to acquire a write lock while holding a read lock) will result in the thread getting completely blocked. Is that a deadlock? You be the judge... But that's the easiest way to create the effect with a single thread.

http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html

Solution 7 - Java

According to Wikipedia, "A deadlock is a situation wherein two or more competing actions are each waiting for the other to finish, and thus neither ever does."

..."In computer science, Coffman deadlock refers to a specific condition when two or more processes are each waiting for each other to release a resource, or more than two processes are waiting for resources in a circular chain."

I think two or more are key words here if you stay strict to definition.

Solution 8 - Java

The JVM only keeps track of the local thread that has the monitor, if the calling class makes an external call back in on itself the incoming call causes the original thread to deadlock itself.

You should be able to run this code to illustrate the idea

import java.rmi.*;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.*;

public class DeadlockThreadExample {

    public static interface DeadlockClass extends Remote {
        public void execute() throws RemoteException;
    }

    public static class DeadlockClassImpl extends UnicastRemoteObject implements DeadlockClass {
        private Object lock = new Object();

        public DeadlockClassImpl() throws RemoteException {
            super();
        }

        public void execute() throws RemoteException {
            try {
                System.out.println("execute()::start");

                synchronized (lock) {
                    System.out.println("execute()::Entered Lock");
                    DeadlockClass deadlockClass = (DeadlockClass) Naming.lookup("rmi://localhost/DeadlockClass");
                    deadlockClass.execute();
                }
                System.out.println("execute()::Exited Lock");
            } catch (NotBoundException e) {
                System.out.println(e.getMessage());
            } catch (java.net.MalformedURLException e) {
                System.out.println(e.getMessage());
            }
            System.out.println("execute()::end");
        }
    }
    
    public static void main(String[] args) throws Exception {
        LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
        DeadlockClassImpl deadlockClassImpl = new DeadlockClassImpl();
        Naming.rebind("DeadlockClass", deadlockClassImpl);
        DeadlockClass deadlockClass = (DeadlockClass) Naming.lookup("rmi://localhost/DeadlockClass");
        deadlockClass.execute();
        System.exit(0);
    }
}

The output from the program looks like

execute()::start
execute()::Entered Lock
execute()::start

Additionally the thread also dump shows the following

"main" prio=6 tid=0x00037fb8 nid=0xb80 runnable [0x0007f000..0x0007fc3c]
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.read(SocketInputStream.java:129)
	at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
	at java.io.BufferedInputStream.read(BufferedInputStream.java:235)
	- locked <0x02fdc568> (a java.io.BufferedInputStream)
	at java.io.DataInputStream.readByte(DataInputStream.java:241)
	

"RMI TCP Connection(4)-172.17.23.165" daemon prio=6 tid=0x0ad83d30 nid=0x1590 waiting for monitor entry [0x0b3cf000..0x0b3cfce8]
	at DeadlockThreadExample$DeadlockClassImpl.execute(DeadlockThreadExample.java:24)
	- waiting to lock <0x0300a848> (a java.lang.Object)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	

"RMI TCP Connection(2)-172.17.23.165" daemon prio=6 tid=0x0ad74008 nid=0x15f0 runnable [0x0b24f000..0x0b24fbe8] 
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.read(SocketInputStream.java:129)
	at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
	at java.io.BufferedInputStream.read(BufferedInputStream.java:235)
	- locked <0x02ffb6d8> (a java.io.BufferedInputStream)
	at java.io.DataInputStream.readByte(DataInputStream.java:241)
	

which indicates that the thread has indeed managed to lock itself

Solution 9 - Java

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.

Solution 10 - Java

While I haven't used Java I have deadlocked a single-thread app before. IIRC: Routine A locked a piece of data to update it. Routine B also locked the same piece of data to update it. Due to requirements changes A ended up calling B. Oops.

Of course this was just an ordinary development bug that I caught the first time I tried to run the code but it did deadlock itself. I would think deadlocks of this type would be possible in any language that supports a filesystem.

Solution 11 - Java

No, because Java implements reentrancy. But please don't mix up concurrency and RMI like that. Synchronization in stubs is something completely different than remote objects that are internally synchronized.

Solution 12 - Java

You can get yourself into a single thread Deadlock with ReentrantReadWriteLock. Write locks can acquire read locks but not the other way around. The following will block indefinitely.

	ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
	lock.readLock().lock();
	lock.writeLock().lock();

Solution 13 - Java

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])

Solution 14 - Java

Ideally a thread should never create a deadlock itself using 'synchronized locks' unless there really is a bug in the JVM itself as 'allegedly' noticed by some people in older versions

Solution 15 - Java

Here's a way for a thread to deadlock itself.

public class DeadlockMe
{
    public static void main(String[] args)
    {
        DeadlockThing foo = new DeadlockThing();
        synchronized(foo)
        {
            try
            {
                foo.wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
}

The thread creates an instance of a class - any class and waits on it. Because the thread created an object with local scope, there's no possible way for any other thread to notify the object to wake up the thread.

Solution 16 - Java

You write a thread which can receive messages from other threads telling it to, for example, terminate. You write code in the thread to monitor other threads and send them terminate messages and wait for a response. The thread would find itself in the list, send itself a message to terminate and wait for itself to terminate. If it wasn't written in a way which prioritised incoming messages over the wait state ...

Solution 17 - Java

If you stretch the definition of the term deadlock: a single thread can find itself blocked on a non-reentrant lock that it took earlier.

Solution 18 - Java

When a thread enters the synchronized block, it checks if the current thread is the owner of the lock, and if it is, the the thread just proceeds without waiting.

So I don't think it is possible.

Solution 19 - Java

I know this is a old post. Here is another example how it could happen if your code has interaction with external resources:

I have a thread, that open a database connection, start a transactionA, and begin update. The same thread, open another connection, start another transactionB. However, because transactionA hasn't committed yet, and it has database table locked, transactionB happens to access this locked table, so it has to wait

In the end the same thread is block by itself because it opened up more than one database connection.


This happened a lot in the application that I work with because there are many modules in the application, and a thread can run though many methods. These methods opens their own connections. Since we had different developers write their code, they may not see the how their code are begin called, and therefore couldn't see the overall database transactions that opened by the application.

Solution 20 - Java

The interviewer was right. A thread can deadlock itself according to JCIP. But how?

In the section 2.3.2 of the JCIP we have the following paragraph about Reentrancy:

> Reentrancy facilitates encapsulation of locking behavior, and > thus simplifies the development of objectͲoriented > concurrentcode. Without reentrantlocks, the very natural-looking code in Listing 2.7, in which a subclass overrides a > synchronized method and then calls the super class method, would deadlock.

The synchronized keyword's lock is a reentrant lock so a thread can lock and unlock in a nested manner but if you use a non-reentrant lock like the following example I wrote as a proof. You will have a deadlock! According to JCIP.

public class SelfDeadLock {

	
	public static class Father{
		volatile protected int n = 0;
		protected Lock ourLock = new Lock();
		
		public void writeSth(){
			try {
				ourLock.lock();
				n++;
				System.out.println("Father class: " + n);
			} catch (InterruptedException ex) {
				Logger.getLogger(SelfDeadLock.class.getName()).log(Level.SEVERE, null, ex);
			}
			ourLock.unlock();
		}
	}
	
	public static class Child extends Father{

		@Override
		public void writeSth() {
			try {
				ourLock.lock();
				n++;
				System.out.println("Child class: " + n);
				super.writeSth();
			} catch (InterruptedException ex) {
				Logger.getLogger(SelfDeadLock.class.getName()).log(Level.SEVERE, null, ex);
			}
			ourLock.unlock();
		}	
	}
	
	public static void main(String[] args) {
		Child child = new Child();
		child.writeSth();
	}
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPramView Question on Stackoverflow
Solution 1 - JavaJustinView Answer on Stackoverflow
Solution 2 - JavaJon SkeetView Answer on Stackoverflow
Solution 3 - JavaAlexander PogrebnyakView Answer on Stackoverflow
Solution 4 - JavafinnwView Answer on Stackoverflow
Solution 5 - JavaPeter LawreyView Answer on Stackoverflow
Solution 6 - JavasjleeView Answer on Stackoverflow
Solution 7 - Javaguiding5View Answer on Stackoverflow
Solution 8 - JavaPramView Answer on Stackoverflow
Solution 9 - JavaTobyView Answer on Stackoverflow
Solution 10 - JavaLoren PechtelView Answer on Stackoverflow
Solution 11 - Javab_erbView Answer on Stackoverflow
Solution 12 - JavamR_fr0gView Answer on Stackoverflow
Solution 13 - JavalabheshrView Answer on Stackoverflow
Solution 14 - JavaGopiView Answer on Stackoverflow
Solution 15 - JavaJeremyPView Answer on Stackoverflow
Solution 16 - JavadwarFishView Answer on Stackoverflow
Solution 17 - JavacarlsborgView Answer on Stackoverflow
Solution 18 - JavaDenis TulskiyView Answer on Stackoverflow
Solution 19 - JavadsumView Answer on Stackoverflow
Solution 20 - JavaJohnnyView Answer on Stackoverflow