Java中的线程在技术上有可能死锁自己吗?
在不久前的一次面试中,我被问到这个问题,我回答说这是不可能的,但面试官告诉我这是可能的。不幸的是,我不能得到他关于如何实现这个死锁的方法。
这让我开始思考,我能想到的唯一情况是,你有一个RMI服务器进程,其中包含一个调用自身的方法。调用该方法的代码行被放在synchronized块中。
这是可能的吗?还是面试官说错了?
我所考虑的源代码就是这样的( testDeadlock在RMI服务器进程中运行)
public boolean testDeadlock () throws RemoteException {
synchronized (this) {
//Call testDeadlock via RMI loopback
}
}
发布于 2010-09-08 17:31:41
JVM只跟踪具有监视器的本地线程,如果调用类在自身内部进行外部回调,则传入调用会导致原始线程自身死锁。
您应该能够运行以下代码来说明这一想法
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);
}
}
程序的输出如下所示
execute()::start
execute()::Entered Lock
execute()::start
此外,线程转储还显示以下内容
"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)
,这表明线程确实已经设法锁定了自己。
发布于 2010-08-16 21:18:47
这取决于你所说的“死锁”到底是什么意思。例如,您可以很容易地在没有任何脉冲的监视器上执行wait()
...但我认为我不会称之为死锁。
按照你的“调用自己的方法”的思路,如果你的服务器只运行一定数量的线程,它们可能都在忙于等待来自同一服务器的响应,如果这算数的话。(最简单的例子:服务器只使用一个线程进行处理。如果您编写一个请求处理程序来调用同一服务器,它将等待被阻塞的线程完成对请求的处理,然后才能为相同的请求提供服务...)这并不是真正的“同步块”类型的死锁,但这确实是一个需要注意的危险。
编辑:要将此答案应用到其他定义中,此处的竞争操作将是“完成当前请求”和“处理新请求”。每个操作都在等待另一个操作的发生。
发布于 2010-08-16 21:49:31
也许面试官在想的是:
Thread.currentThread().join();
然而,我认为这不能算作死锁。
https://stackoverflow.com/questions/3493441
复制相似问题