Java 线程是否可能自行死锁?
从技术上讲,Java中的线程是否可以自行死锁 不久前我在一次采访中被问到这一点,回答说这是不可能的,但采访者告诉我这是可能的。不幸的是,我无法得到他关于如何实现这个僵局的方法Java 线程是否可能自行死锁?,java,multithreading,deadlock,rmi,Java,Multithreading,Deadlock,Rmi,从技术上讲,Java中的线程是否可以自行死锁 不久前我在一次采访中被问到这一点,回答说这是不可能的,但采访者告诉我这是可能的。不幸的是,我无法得到他关于如何实现这个僵局的方法 Deadlock detected ================= "Negotiator-Thread-1": waiting to lock Monitor of com.google.code.tempusfugit.concurrency.DeadlockDetectorTest$Cat@ce4a8a
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"
这引起了我的思考,我能想到的唯一一种情况是,在哪里可以发生这种情况,就是在哪里有一个RMI服务器进程,其中包含一个调用自身的方法。调用该方法的代码行放置在同步块中
这是可能的,还是面试官不正确
我考虑的源代码大致如下(testDeadlock在RMI服务器进程中运行)
这完全取决于你所说的“死锁”是什么意思。例如,您可以轻松地
wait()
在没有任何脉冲的监视器上。。。但我不认为我会称之为僵局
按照您的“调用自身的方法”行思考,如果您的服务器只运行了一定数量的线程,那么它们可能都在忙于等待来自同一服务器的响应(如果这算上的话)。(最简单的示例:服务器仅使用一个线程进行处理。如果您编写一个请求处理程序,调用同一个服务器,它将等待被阻止的线程完成处理请求,然后才能服务于同一个请求…)这并不是真正的“同步块”死锁,但这确实是一个需要注意的危险
编辑:要将此答案应用于其他答案中的定义,此处的竞争操作将是“完成当前请求”和“处理新请求”。每个动作都在等待另一个动作的发生。也许他指的是锁本身,那当然太容易了:
synchronized( this )
{
wait( );
}
根据以下定义: 死锁是两个或多个相互竞争的操作各自等待另一个完成的情况 我想说的是答案是否定的——一个线程可以无限期地坐在那里等待某件事情,但是除非两个相互竞争的动作在等待对方,否则根据定义,这不是死锁
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"
除非有人向我解释一个线程如何同时等待两个操作完成
更新:我能想到的唯一可能的情况是某种消息泵,线程处理一条消息,要求它无限期地等待某事发生,实际上某事将由消息泵上的另一条消息处理
这种(令人难以置信的人为设计)场景在技术上可能被称为死锁。理想情况下,线程不应该使用“同步锁”自行创建死锁,除非JVM本身真的存在缺陷,就像一些人在旧版本中所说的那样。根据维基百科,“僵局是指两个或多个相互竞争的行动都在等待对方完成,因此双方都没有完成。”
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"
…“在计算机科学中,Coffman死锁是指两个或多个进程各自等待对方释放资源,或两个以上进程在循环链中等待资源时的一种特定情况。”
如果你严格定义的话,我认为两个或两个以上的是这里的关键词。不,因为Java实现了可重入性。但是请不要把并发性和RMI混为一谈。存根中的同步与内部同步的远程对象完全不同。可能是什么意思rviewer想到的是:
Thread.currentThread().join();
然而,我认为这不算死锁。虽然我没有使用Java,但我以前已经死锁了一个单线程应用程序。IIRC:例程a锁定了一段数据来更新它。例程B也锁定了同一段数据来更新它。由于需求变化,a最终调用了B。Oops
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"
当然,这只是我第一次尝试运行代码时发现的一个普通的开发错误,但它本身确实存在死锁。我认为这种类型的死锁在任何支持文件系统的语言中都是可能的。从读锁升级到写锁(在持有读锁的同时尝试获取写锁)将导致线程被完全阻塞。这是死锁吗?由你来判断……但这是用单个线程创建效果的最简单方法
以下是线程死锁的一种方法
public class DeadlockMe
{
public static void main(String[] args)
{
DeadlockThing foo = new DeadlockThing();
synchronized(foo)
{
try
{
foo.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
线程创建一个类的实例(任何类)并等待它。因为线程创建了一个具有本地作用域的对象,所以任何其他线程都不可能通知该对象唤醒线程。您编写的线程可以接收来自其他线程的消息,例如,通知它终止。您在e线程监视其他线程并向它们发送终止消息并等待响应。该线程会在列表中找到自己,向自己发送一条消息以终止并等待自己终止。如果它的编写方式没有将传入消息优先于等待状态…如果您扩展术语死锁的定义:单个线程可能会发现自己被先前使用的不可重入锁阻塞。当线程进入同步块时,它会检查当前线程是否是锁的所有者,如果是,则线程只会继续,而不等待
因此我认为这是不可能的。JVM只跟踪具有监视器的本地线程,如果调用类对自身进行外部调用,则传入调用会导致原始线程自身死锁
public class DeadlockMe
{
public static void main(String[] args)
{
DeadlockThing foo = new DeadlockThing();
synchronized(foo)
{
try
{
foo.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
您应该能够运行此代码来说明这个想法
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)
“主”优先级=6 tid=0x00037fb8 nid=0xb8
"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)
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])