【问题标题】:Deadlock in a single threaded java program [duplicate]单线程Java程序中的死锁[重复]
【发布时间】:2010-10-14 07:02:18
【问题描述】:

了解死锁可能发生在单线程 Java 程序中。我想知道毕竟不会有任何竞争。据我所知,书籍举例说明了不止一个线程。如果可以在单个线程中发生,请举例说明。

【问题讨论】:

    标签: java deadlock


    【解决方案1】:

    这取决于您如何准确定义“死锁”。

    例如,这个场景有点现实:一个单线程应用程序使用一个大小有限的队列,当达到其限制时会阻塞。只要未达到限制,这将适用于单个线程。但是当达到限制时,线程将永远等待(不存在的)其他线程从队列中取出一些东西,以便它可以继续。

    【讨论】:

    • 我不认为这是一个僵局。否则while(true){} 是死锁
    • @Bozho 是阻塞,不是死锁,但while (true) 和它无关。
    【解决方案2】:

    在多核处理器变得便宜之前,所有的台式电脑都是单核处理器。单核处理器仅在线程上运行。那么多线程是如何工作的呢? 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);
    

    是的,单线程程序中可能会出现死锁。

    【讨论】:

    • 这种死锁不是每次都会发生吗?
    • 使用这 2 个“线程”和 yield(),它将随机发生,使用现代操作系统(不使用 yield(),但使用抢占线程),它可以使用第二个单线程解决方案,每次都会发生死锁,只需将我的 'queue.xxxx()' 方法替换为 BlockingQueue 中的适当方法即可。线程会认为它在等待其他线程,而它在等待自己。 :-)
    • 在单线程环境中使用 yield() 可以完成多线程这一事实不会影响问题域。问题不是关于多线程情况,而是关于单线程情况。
    【解决方案3】:

    我敢说是的

    如果你尝试在同一个线程中连续获取同一个锁,它是否检查锁是否被同一个线程获取取决于锁的类型或锁定实现。如果实现没有检查这一点,你就有了死锁。

    对于同步,这已检查,但我找不到信号量的保证。

    如果您使用其他类型的锁,则必须检查规范以确保其行为方式!

    正如已经指出的,您可以通过读取/写入受限缓冲区来阻塞(这与死锁不同)。例如,您将内容写入有槽的缓冲区,并且仅在某些条件下从其中读取。当您无法再插入时,您将等到一个插槽空闲,这不会发生,因为您自己会读取。

    所以我敢说答案应该是肯定的,尽管不是那么容易而且通常更容易被发现。

    马里奥

    【讨论】:

      【解决方案4】:

      即使你的 java 东西是单线程的,仍然有信号处理程序,它们在与主线程不同的线程/上下文中执行。

      因此,如果/当 java 在 linux 上运行时,即使在单线程解决方案上也确实会发生死锁。

      QED。 -pbr

      【讨论】:

      • +1 没有考虑信号!
      【解决方案5】:

      不,对我来说这听起来很不可能。

      但理论上,您可以锁定系统资源,而另一个应用程序锁定您要请求的另一个应用程序,而该应用程序将请求您已锁定的资源。 死锁。

      但是操作系统应该能够通过检测来解决这个问题,并将这两种资源同时提供给一个应用程序。发生这种情况的机会微乎其微,但任何好的操作系统都应该能够处理这种十亿分之一的机会。

      如果您仔细设计并且一次只锁定一个资源,则不会发生这种情况。

      【讨论】:

      • 为什么投反对票?这个答案准确地讨论了十亿分之一可能发生的事情。
      • 我没有对你投反对票,但我差点投了票。您的第二段是正确的,因此如果应用程序的设计以您描述的方式运行,发生这种情况的可能性非常高。所以你的第 3 段是 wrong (对于大多数操作系统上的大多数资源)。毕竟,操作系统究竟会做什么来避免死锁?
      • 您的第 3 段假定应用程序可以仅使用单一资源来实现其目标,这根本无法解决大量问题。
      • 操作系统可以进行资源调度,但这在程序员的头脑中是相当困难的。或者至少当我 7 年前做一个爱好内核时,这对我来说很难。大多数情况下,最坏的情况是两个进程都对他们锁定的资源做了一些事情——如果是这样,一个人不能只是将其中一个资源交给另一个进程并让它去。我自己 7 年前所做的解决方案很粗糙 - 它只是抛硬币并寄希望于最好的结果。
      【解决方案6】:

      没有。

      死锁是多个线程(或进程)尝试获取锁的结果,而这两者都无法继续。

      考虑引用维基百科文章中的一句话:(http://en.wikipedia.org/wiki/Deadlock)

      “当两列火车在交叉口相互接近时,两列火车都应完全停止,直到另一列离开后才重新启动。”

      【讨论】:

      • 多线程或进程....
      • 好点卡特。我已经编辑了我的评论。谢谢。
      • 是的,好吧,多个(即超过 0 个)线程,这就是我们所说的。
      【解决方案7】:

      其实很简单:

      BlockingQueue bq = new ArrayBlockingQueue(1);
      bq.take();
      

      会死锁。

      【讨论】:

      • 这不是死锁。这是一个块。
      • @EJP 吹毛求疵。执行此操作的线程已死。这么简单。
      猜你喜欢
      • 1970-01-01
      • 2016-01-28
      • 1970-01-01
      • 2014-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多