【发布时间】:2010-10-14 07:02:18
【问题描述】:
了解死锁可能发生在单线程 Java 程序中。我想知道毕竟不会有任何竞争。据我所知,书籍举例说明了不止一个线程。如果可以在单个线程中发生,请举例说明。
【问题讨论】:
了解死锁可能发生在单线程 Java 程序中。我想知道毕竟不会有任何竞争。据我所知,书籍举例说明了不止一个线程。如果可以在单个线程中发生,请举例说明。
【问题讨论】:
这取决于您如何准确定义“死锁”。
例如,这个场景有点现实:一个单线程应用程序使用一个大小有限的队列,当达到其限制时会阻塞。只要未达到限制,这将适用于单个线程。但是当达到限制时,线程将永远等待(不存在的)其他线程从队列中取出一些东西,以便它可以继续。
【讨论】:
while(true){} 是死锁
while (true) 和它无关。
在多核处理器变得便宜之前,所有的台式电脑都是单核处理器。单核处理器仅在线程上运行。那么多线程是如何工作的呢? Java 最简单的实现是:
thread1的代码:
doSomething();
yield(); // may switch to another thread
doSomethingElse();
thread2的代码:
doSomething2();
yield(); // may switch to another thread
doSomethingElse2();
这称为协作多线程 - 只需 1 个线程即可完成,因此多线程是在 Windows 3.1 中完成的。
今天的多线程称为抢占式多线程只是对协作多线程的轻微修改,其中该 yield() 会不时自动调用。
所有这些都可能简化为以下交错:
doSomething();
doSomething2();
doSomethingElse2();
doSomethingElse();
或:
doSomething();
doSomething2();
doSomethingElse();
doSomethingElse2();
等等...我们将多线程代码转换为单线程代码。所以是的,如果在单线程中的多线程程序中也可能出现死锁。例如:
线程1:
queue.put(x);
yield();
线程2:
x = queue.waitAndGet()
yield();
这个交错没问题:
queue.put(x);
x = queue.waitAndGet()
但是在这里我们遇到了死锁:
x = queue.waitAndGet()
queue.put(x);
是的,单线程程序中可能会出现死锁。
【讨论】:
我敢说是的
如果你尝试在同一个线程中连续获取同一个锁,它是否检查锁是否被同一个线程获取取决于锁的类型或锁定实现。如果实现没有检查这一点,你就有了死锁。
对于同步,这已检查,但我找不到信号量的保证。
如果您使用其他类型的锁,则必须检查规范以确保其行为方式!
正如已经指出的,您可以通过读取/写入受限缓冲区来阻塞(这与死锁不同)。例如,您将内容写入有槽的缓冲区,并且仅在某些条件下从其中读取。当您无法再插入时,您将等到一个插槽空闲,这不会发生,因为您自己会读取。
所以我敢说答案应该是肯定的,尽管不是那么容易而且通常更容易被发现。
第
马里奥
【讨论】:
即使你的 java 东西是单线程的,仍然有信号处理程序,它们在与主线程不同的线程/上下文中执行。
因此,如果/当 java 在 linux 上运行时,即使在单线程解决方案上也确实会发生死锁。
QED。 -pbr
【讨论】:
不,对我来说这听起来很不可能。
但理论上,您可以锁定系统资源,而另一个应用程序锁定您要请求的另一个应用程序,而该应用程序将请求您已锁定的资源。 砰死锁。
但是操作系统应该能够通过检测来解决这个问题,并将这两种资源同时提供给一个应用程序。发生这种情况的机会微乎其微,但任何好的操作系统都应该能够处理这种十亿分之一的机会。
如果您仔细设计并且一次只锁定一个资源,则不会发生这种情况。
【讨论】:
没有。
死锁是多个线程(或进程)尝试获取锁的结果,而这两者都无法继续。
考虑引用维基百科文章中的一句话:(http://en.wikipedia.org/wiki/Deadlock)
“当两列火车在交叉口相互接近时,两列火车都应完全停止,直到另一列离开后才重新启动。”
【讨论】:
其实很简单:
BlockingQueue bq = new ArrayBlockingQueue(1);
bq.take();
会死锁。
【讨论】: