java 线程本身是否有可能发生死锁?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3493441/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible for a thread to Deadlock itself?
提问by Pram
Is it technically possible for a thread in Java to deadlock itself?
Java 中的线程在技术上是否可能死锁?
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.
这让我开始思考,我能想到的唯一情况是您可以在何处发生这种情况,即您有一个 RMI 服务器进程,其中包含一个调用自身的方法。调用该方法的代码行放置在一个同步块中。
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)
我正在考虑的源代码是这样的(其中 testDeadlock 在 RMI 服务器进程中运行)
public boolean testDeadlock () throws RemoteException {
synchronized (this) {
//Call testDeadlock via RMI loopback
}
}
采纳答案by Pram
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.
JVM 只跟踪具有监视器的本地线程,如果调用类对自身进行外部调用,则传入调用会导致原始线程自身死锁。
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
这表明线程确实设法锁定了自己
回答by Justin
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 twocompeting 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 somethingto happen, where in fact that somethingwill be processed by another message on the message pump.
UPDATE:唯一可能的情况下,我能想到的是某种消息泵,其中一个线程处理,要求其无限期地等待消息的事情发生,在这里其实是一些将通过在消息泵的另一个消息被处理.
This (incredibly contrived) scenario could possibly be technically called a deadlock.
这种(令人难以置信的人为设计)场景在技术上可能被称为僵局。
回答by Jon Skeet
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.
这完全取决于您所说的“死锁”是什么意思。例如,您可以轻松地wait()在没有任何东西脉冲的监视器上...但我认为我不会将这种情况称为死锁。
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.
编辑:要将此答案应用于其他定义中的定义,此处的竞争操作将是“完成当前请求”和“处理新请求”。每个动作都在等待另一个动作发生。
回答by Alexander Pogrebnyak
Maybe he meant LOCKitself, that's certainly too easy:
也许他的意思是LOCK本身,那当然太简单了:
synchronized( this )
{
wait( );
}
回答by finnw
Maybe what the interviewer was thinking of was:
可能面试官在想的是:
Thread.currentThread().join();
However I would argue that it does not count as a deadlock.
但是,我认为这不算是僵局。
回答by Peter Lawrey
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 livelockwhich is similar to a deadlock, but not the same by definition.
当一个线程自身进入资源 staving 状态时,它被称为活锁,类似于死锁,但根据定义不同。
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.
活锁的一个例子是使用 ReentrantReadWriteLock。尽管在读或写上是可重入的,但它不允许将锁从读升级到写。
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.
一个相关的问题是;线程是否可以在不创建额外线程的情况下陷入死锁。这是可能的,因为有后台线程,例如终结器线程,可以在后台运行用户代码。这允许主线程和终结器线程彼此死锁。
回答by sjlee
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
http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html
回答by guiding5
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."
...“在计算机科学中,Coffman 死锁是指当两个或多个进程各自等待对方释放资源,或两个以上进程在循环链中等待资源时的特定情况。”
I think two or moreare key words here if you stay strict to definition.
如果您严格遵守定义,我认为两个或更多是这里的关键词。
回答by Toby
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.
我建议在 Java 中,您可以依赖 Java 的定义(这与两个线程的想法一致)。如果 JVM检测到死锁本身,则最终判断者可能是 JVM 。因此,在Pram 的示例中,如果是真正的死锁,线程将显示如下内容。
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 Lockbased cyclic deadlocks since 1.6.
自 1.5 以来,这种死锁检测可用于内在锁,Lock自 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.
一个持续阻塞的资源,或者至少是等待永远不会发生的事情的东西被称为活锁。类似的问题,VM 之外的进程(例如)数据库死锁是完全可能的,但我认为不适合这个问题。
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.
在回答您最初的问题时,探戈需要两个人,我建议不应将婴儿车的答案标记为正确,因为它不是!;) 回调的 RMI 线程可能会导致阻塞,但它运行在与主线程不同的线程上(由 RMI 服务器管理)。即使主线程没有明确设置另一个线程,也会涉及两个线程。没有死锁,因为在线程转储中缺少检测(或者如果您在 jconsole 中单击“检测死锁”),它会更准确地描述为活锁。
Having said all that, any discussion along the lines of each of these answers would be enough to satisfy me as an interviewer.
话虽如此,按照这些答案中的每一个进行的任何讨论都足以让我作为面试官感到满意。
回答by Loren Pechtel
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.
虽然我没有使用过 Java,但我之前已经使单线程应用程序陷入僵局。IIRC:例程 A 锁定了一条数据以对其进行更新。例程 B 还锁定了同一条数据以对其进行更新。由于需求变化,A 最终打电话给 B。哎呀。
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.
当然,这只是我第一次尝试运行代码时发现的一个普通的开发错误,但它本身确实陷入了死锁。我认为这种类型的死锁在任何支持文件系统的语言中都是可能的。

