两个线程在同一个监视器上等待,例如,如果一个线程调用等待锁,而另一个获取监视器的线程在通知第一个线程之前也调用等待。现在两个线程都在等待,但是没有人得到通知。我该怎么称呼这种情况?这能叫僵局吗?
编辑:假设只有这两个线程,并且无法从其他地方通知它们
更新:我刚刚创建了我在问题中描述的情况。当转换器线程在侦听器线程之前启动时,以下代码大部分时间都正常工作。然而,当我在changer之前启动listener时,程序在打印两行(一行来自changer,另一行来自listener线程)后挂起。我在更改之前调用侦听器的情况会被称为死锁吗
package demo;
public class ProducerConsumer {
public static int SAMPLE_INT = 0;
public static void main(String[] args) {
PC pc = new PC();
Thread changer = new Thread(new Runnable() {
public void run(){
try {
pc.producer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread listener = new Thread(new Runnable(){
public void run() {
try {
pc.consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
changer.start();
listener.start();
}
}
class PC {
Object lock = new Object();
public void producer() throws InterruptedException {
synchronized(this){
for (int i=0; i<5; i++){
ProducerConsumer.SAMPLE_INT++;
System.out.println("Changed value of int to: " + ProducerConsumer.SAMPLE_INT);
wait();
notify();
}
}
}
public void consumer() throws InterruptedException{
synchronized(this){
for (int i=0; i<5; i++){
System.out.println("Receieved Change: " + ProducerConsumer.SAMPLE_INT);
notify();
wait();
}
}
}
}
在侦听器之前启动转换器时输出:
将int值更改为:1
接收的更改:1
将int值更改为:2
接收的更改:2
将int值更改为:3
接收的更改:3
将int值更改为:4
将int值更改为:5
接收的更改:5
程序终止
在转换器之前启动侦听器时的输出:
接收到的更改:0
将int的值更改为:1
程序不会终止。
谢谢
死锁基本上是指一个线程持有一个锁(第一个锁),然后想要获得另一个锁(第二个锁),但它永远无法获得,因为第二个锁被另一个想要获得第一个锁的线程持有。这也可能发生在线程链中,例如,Thread1有LockA,Thread2有LockB,Thread3有LockC,并且它们正在等待其他线程持有的锁(例如,Thread1想要LockB,Thread2想要LockC,而Thread3想要LockA)。在这种情况下,没有一个线程可以继续。
只有这种情况才被称为死锁;持有一个锁的线程等待另一个锁,除非释放它的锁,否则该锁永远不会被获取。
对lock对象调用wait
,从技术上释放线程所持有的锁。
所以,为了回答你的问题,我认为你不能把问题中提到的场景称为死锁。
这不是死锁,因为有办法摆脱这种情况——如果第三个线程调用通知()
或通知所有()
,那么前两个等待线程将返回到就绪状态。
死锁通常无法在应用程序本身内解决,需要重新启动。
这就是为什么我不会称你的处境为僵局。
还有两个术语描述线程协调问题:
生存与饥饿
下面是LoveLock和饥饿的确切定义——饥饿和活锁
这也不是一个活锁,因为线程之间没有响应。
你的处境可能与饥饿这个词最接近,但并不完全是饥饿。饥饿是指线程等待占用了很长时间的资源。在您的情况下,资源是对象的锁,它将永远不会被再次获取。所以你最好的办法就是“无休止的饥饿”。
我个人认为这是生产者-消费者错误,因为等待通知机制描述和管理生产者-消费者模式的线程协调,这种方法(没有通知的等待)只是开发人员错误或方法的误用。
如果仅涉及这两个线程(如访问监视器),则为是。如果有其他线程可以访问监视器并将其解锁,则没有。
但是请记住,您讨论的是两个主题—监视器通常是线程术语中的互斥体。但是,wait
是一种与条件变量相关的东西,它在要求互斥锁工作的同时,执行一项更微妙的任务,根据一个线程向另一个线程发出警告信号的条件故意阻塞线程,这种情况称为虚假唤醒。
问题内容: 当前,我们正在分析tomcat线程转储。在tomcat上同时运行的所有线程的单线程转储包含以下行: 特别是我们不明白 根据我们的理解,它说三个线程当时正在锁定同一监视器。根据我们的理解,根据JLS,这是不可能的。 我们对线程转储的解释正确吗? 问题答案: 看起来所有这些线程都在等待与监视器关联的条件,即它们称为该监视器的方法。 当线程在其拥有的监视器上调用时,它会临时释放监视器,并在从
我做了几个线程转储,发现有16个线程在等待同一个锁,例如: “__ejb-thread-pool1”守护进程prio=6 tid=0x39657c00 nid=0x1c08在条件[0x3297f000]java.lang.thread.state:waiting(parking)在sun.misc.unsafe.park(本机方法)-在java.util.concurrent.locks.lock
我写了一个启动两个线程的代码片段;一个线程打印所有奇数,而另一个线程打印所有偶数。我使用了内在锁和线程通信命令的组合来实现两个线程的正确交叉。这是我的代码, 以下是我的问题: > 奇数线程在printOdd()函数中执行,而偶数线程在print偶数()函数中执行。我对两个线程都使用一个内在锁;我不明白两个线程怎么能同时存在于各自的同步块中,因为使用了相同的锁。 我从代码中删除了线程通信语句(通知,
问题内容: 我一直在弄乱Java中的线程来处理它们(这似乎是最好的方法),现在了解了sync,wait()和notify()的情况。 我很好奇是否有一种方法可以同时对两个资源进行wait()。我认为以下内容并不能完全满足我的想法( 编辑 : 请注意,此示例中省略了通常的while循环,仅专注于释放两个资源 ): 在这种(非常人为)情况下,将保留token2直到返回token1,然后将保留token
问题内容: 工作中的某个人只是问了要在同步对象中包装等待的原因。 老实说,我看不出推理的原因。我了解javadocs所说的内容- 该线程需要成为对象监视器的所有者,但是为什么呢?它可以防止什么问题?(如果确实有必要,为什么wait方法不能获取监视器本身?) 我正在寻找一个相当深入的原因,或者可能是一篇文章的参考。我无法在快速的Google中找到一个。 哦,还有,thread.sleep比较起来如何
我试图使用Java同步“原语”(synchronized,wait(),notify())实现类似于Java的有界BlockingQueue接口的东西,这时我偶然发现了一些我不理解的行为。 我创建了一个能够存储 1 个元素的队列,创建两个等待从队列中获取值的线程,启动它们,然后尝试将两个值放入主线程同步块中的队列中。大多数情况下它可以工作,但有时等待值的两个线程开始似乎相互唤醒并且不让主线程进入同