Is it possible for a thread to Deadlock itself?

后端 未结 20 1321
暗喜
暗喜 2020-12-02 09:29

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 inte

相关标签:
20条回答
  • 2020-12-02 09:43

    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();
        }
    }
    
    0 讨论(0)
  • 2020-12-02 09:45

    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

    0 讨论(0)
  • 2020-12-02 09:50

    Maybe what the interviewer was thinking of was:

    Thread.currentThread().join();
    

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

    0 讨论(0)
  • 2020-12-02 09:51

    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

    0 讨论(0)
  • 2020-12-02 09:52

    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.

    0 讨论(0)
  • 2020-12-02 09:52

    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

    0 讨论(0)
提交回复
热议问题