views:

1177

answers:

15

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 acheive 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            
    }
}
+13  A: 

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.

Jon Skeet
+6  A: 

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

synchronized( this )
{
    wait( );
}
Alexander Pogrebnyak
He just asked is it **technically possible** for a thread to lock it self, not whether it may appear in RL very often. +1
FUZxxl
I upvoted this, but it doesn't deadlock the thread. Another thread only has to notify the object.
JeremyP
@JeremyP. That's the point, you cannot deadlock 1 thread, see the post by Kragen here. On the other hand, if you only have a single thread, then calling `wait()` will definitely lock it, and without cooperation of other thread it will not be able to proceed.
Alexander Pogrebnyak
@Alexander Pogrebnyak: Your example is different from mine in that theoretically, another thread could unlock the the one that runs your code. My example represents a kind of degenerate case that cannot be unlocked by another thread. I don't see why the "two competing actions" need to be in separate threads.
JeremyP
+30  A: 

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.

Kragen
+1. Agree that you need two to tango ( I mean deadlock ), but just only 1 to hang itself.
Alexander Pogrebnyak
+1 to Kragen for the explanation, +1 to Alexander for the tl;dr version.
rownage
I would consider some of the scenarios involving one thread and a message pump to constitute deadlock. The current thread is one 'thing', the queue of messages is another; the main thread may wait for a message in the queue to do something which can't happen while the main thread waits. If the message queue supports priorities, a locked situation may arise if processing a message before a low-priority message is processed will reenqueue that message at high priority.
supercat
Funny you should mention that particularly contrived scenario, Kragen, as that happened to me just a few weeks ago (though it wasn't Java). I had a heck of a time convincing my co-workers that not only had it happened, but that it was possible at all.
Kaz Dragon
A: 

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

Gopi
+5  A: 

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 is a key word here if you stay strict to definition.

guiding5
A: 

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.

PartlyCloudy
+4  A: 

Maybe what the interviewer was thinking of was:

Thread.currentThread().join();

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

finnw
+2  A: 

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.

Loren Pechtel
I was going to write the same thing.
darron
+4  A: 

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

sjlee
+2  A: 

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.

JeremyP
Once again, it's locked, hanged, but not DEADLOCKED. See the definition of deadlock in Kragen's post. Also, according to your own logic, this thread is not deadlocked. The OTHER thread only has to interrupt the waiting thread, so it becomes unlocked.
Alexander Pogrebnyak
@Alexander Pogrebnyak: that's pedantry. Kragen's post says competing actions, not competing threads or processes. Also, if you say a thread that can be interrupted is not deadlocked, then no thread can be deadlocked.
JeremyP
A: 

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

dwarFish
A: 
Angkor Wat
A: 

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.

tholomew
A: 

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.

tulskiy
+1  A: 

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

Pram