我读到单个用户线程可以使用系统线程死锁。 我的问题是,这个系统线程可以是与java线程共享资源的任何线程(不一定是java线程)。例如。 :锁定文件后I / O在2个文件上。 因此,除非系统线程与java线程共享资源,否则它无法创建死锁。 是否有上述声明中的任何其他示例以粗体显示。
另一个问题:
如果有2个函数使用2个锁,它们应该以相同的顺序锁定。但是必须以相同的相反顺序发布。两种功能的锁定释放顺序是否不同 例如:
function1() {
try {
lock1.lock();
lock2.lock();
} finally {
lock2.unlock();
lock1.unlock();
}
}
function2() {
try {
lock1.lock();
lock2.lock();
} finally {
lock1.unlock();
lock2.unlock();
}
}
参考链接:if a single user thread deadlocks, a system thread must also be involved
答案 0 :(得分:3)
如果仅涉及Java对象监视器锁
,则单个Java线程无法对其自身死锁是正确的。“系统线程”的含义并不完全清楚。即使在运行简单程序时,JVM也会运行多个线程,例如终结器线程,或者用于GUI应用程序,即事件分发线程(EDT)。这些线程可能会占用Java对象监视器锁,因此会对单个应用程序线程造成死锁。
单个Java线程可以对外部进程死锁,而不是其他Java线程。例如,请考虑以下程序:
public static void main(String[] args) throws Exception {
Process proc = Runtime.getRuntime().exec("cat");
byte[] buffer = new byte[100_000];
OutputStream out = proc.getOutputStream();
out.write(buffer);
out.close();
InputStream in = proc.getInputStream();
int count = in.read(buffer);
System.out.println(count);
}
这会运行“cat”,它只是从stdin复制到stdout。该程序通常会死锁,因为它会将大量数据写入子进程。子进程将阻止写入其输出,因为父进程尚未读取它。这可以防止子进程读取其所有输入。因此,Java线程已经对子进程陷入僵局。 (处理这种情况的常用方法是让另一个Java线程读取子进程输出。)
如果单个Java线程正在等待从未发生的通知,则它可能会死锁。考虑:
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
synchronized (obj) {
obj.wait();
}
}
此程序永远不会终止,因为没有任何东西会通知obj或中断线程。这似乎有点人为,但这种“失败的唤醒问题”的实例确实在实践中发生。有错误的系统可能无法正确设置状态,或者在错误的时间拨打notify
,或拨打notify
而不是notifyAll
,在wait
电话中阻止线程等待永远不会发生的通知。在这种情况下,可能很难识别该线程死锁的另一个线程,因为该线程可能在过去已经死亡,或者它可能尚未创建。但它肯定是僵局。
<强>更新强>
我遇到了另一个单线程死锁的例子。 Goetz等。 al。, Java Concurrency In Practice p。 215,描述线程饥饿死锁。考虑一个
的例子提交任务并等待其结果的任务在单线程
Executor
中执行。在这种情况下,第一个任务将永远等待,永久停止该任务,所有其他任务等待在Executor
执行。
(单线程Executor
基本上是一个处理任务队列的线程,一次一个。)
更新2
我在文献中找到了另一个单线程死锁的例子:
兰普森,巴特勒W.和大卫D.雷德尔。 在Mesa中使用过程和监视器的经验。 CACM Vol。 1980年2月23日第2期。使用监视器可以发生三种成对死锁模式。当然,在实践中,死锁通常涉及两个以上的过程,在这种情况下,观察到的实际模式往往更复杂;相反,单个进程也可能与自身发生死锁(例如,如果一个入口过程是递归的)。
请注意,在本文中,“进程”指的是我们称之为线程的内容,而“入口过程”就像是同步方法。但是,在Mesa中,监视器不可重入,因此如果单个线程第二次尝试进入同一监视器,则单个线程可能会死锁。
Posix线程也是如此。如果一个线程在正常(即非递归)互斥锁上第二次调用pthread_mutex_lock
,则该线程将自行死锁。
从这些例子中,我得出结论,“死锁”并不严格要求两个或多个线程。
答案 1 :(得分:1)
对于第一个问题:想想任何Swing应用程序。例如,主线程可能容易干扰事件调度线程(因为所有事件处理都发生在该特定线程中)。此外,您可以使用终结器线程。
对于第二个问题:是的,你可以按任何顺序释放锁。