【问题标题】:Why is this code deadlocking? [closed]为什么这段代码会死锁? [关闭]
【发布时间】:2012-06-03 12:56:17
【问题描述】:

我需要一些有关死锁的帮助。我只是不明白为什么我的代码在这里死锁。

我尝试了不同的场景。

但是我仍然找不到问题的原因和位置。通常它应该工作 而且我没有找到debutertermine 之间的死锁。

  public class Interblocking {
           protected object obj = object();
           private boolean condition = true;

           public synchronized void debuter() {
               synchronized(obj) {
                   while (!condition) {
                       try {
                           obj.wait();
                       } catch (InterruptedExeption ie) {}
                   }
                   condition = false;
               }
           }

           public synchronized void terminer() {
               synchronized(obj) {
                   condition = true;
                   obj.notifyAll();
               }
           }
        }

【问题讨论】:

  • 好吧,鉴于你还没有说这门课的目的是什么,这个问题很难回答……
  • 为什么下面的指定类描述了一个典型的死锁案例?给出一个场景来说明这种默认设置。
  • 这就是问题 ;) 我很难理解
  • 是作业吗?如果是这样,请将其标记为作业。此外,如果有一些线程在做事,可能会出现死锁。你的线程对这个类做了什么?
  • 是的,这是一个家庭作业,给定的陈述是我在不知道线程在做什么之前解释的,我只知道必须有 thread1 T1,thread2 T2,thread3 T3 ... 等等上

标签: java multithreading locking


【解决方案1】:

编辑(新答案)

方法wait() 不会释放当前线程的所有锁。

所以当一个线程调用debuter时,它只释放obj锁,但持有this锁,所以其他线程不能调用terminer方法。

示例如下:

class WaitReleaseTest implements Runnable {
    Object lockA, lockB;
    public WaitReleaseTest(Object lockA, Object lockB) {
        this.lockA = lockA;
        this.lockB = lockB;
    }

    public void run() {
        System.out.println(Thread.currentThread().getName()
                + " attempting to acquire lockA");
        synchronized (lockA) {
            System.out.println(Thread.currentThread().getName()
                    + " attempting to acquire lockB");
            synchronized (lockB) {
                System.out.println(Thread.currentThread().getName()
                        + " holds lockA = " + Thread.holdsLock(lockA));
                System.out.println(Thread.currentThread().getName()
                        + " holds lockB = " + Thread.holdsLock(lockB));
                try {
                    lockB.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Object o1=new Object();
        Object o2=new Object();
        new Thread(new WaitReleaseTest(o1,o2)).start();
        TimeUnit.MILLISECONDS.sleep(500);
        new Thread(new WaitReleaseTest(o1,o2)).start();
    }
}

输出

Thread-0 attempting to acquire lockA
Thread-0 attempting to acquire lockB
Thread-0 holds lockA = true
Thread-0 holds lockB = true
Thread-1 attempting to acquire lockA
... now it waits

【讨论】:

  • 非常感谢,因为我知道这是绕过死锁的解决方案
  • @Dardan JB Nizet 是对的,所以我的回答无法解决您的问题。
  • 是这样吗?您在这里有两个锁: 类 interblocking 的实例(因为您正在使用同步方法。) obj 的实例(因为您正在使用 synchronized(obj) 然后等待并通知它。现在,如果线程 A 去首发() 方法并等待 obj,线程 B 不能去 terminer() 执行 obj.notifyAll() 因为线程 A 仍然持有 interblocking 类实例的监视器锁。因此它死锁。
  • @Dardan 你刚刚回答了你的问题。我认为 wait() 会释放所有线程锁,但事实并非如此。所以当A线程调用debuter时,它只释放obj锁但持有this锁,所以其他线程不能调用terminer
【解决方案2】:

代码不包含死锁条件。当资源图中存在循环时,就会发生死锁。您只有一个资源 (obj),因此资源图由单个节点组成,不能包含循环。

虽然debuter 可能会等待condition,但terminer 不会等待很长时间。

【讨论】:

  • 那是错误的。线程在debuter中时不会执行终止器。
  • 是的,我错了。我只是注意到方法在 this 和 obj 上同步。应该只对一个对象进行同步,无论是 this 还是 obj。
【解决方案3】:

我猜你的代码与你的代码能够做的完全不同。

您可能希望进入 debuter 的线程等到 condition 为真;

基本问题是方法上的 synchronized 关键字。他们确保只有线程在您的 Interblocking

实例的任何方法中

删除方法上的同步

下一个问题是条件。未定义线程在调用终结器后如何释放

您在第二次调用 debuter 时遇到死锁,因为在第一次调用 debutercondition 为 false。 并且没有办法执行终止器,因为debuter中有线程阻塞

使用多级阻塞对象(在本例中为 object 和 this)总是有可能导致死锁。

【讨论】:

  • 我不必让这段代码工作我只需要回答为什么这段代码会执行死锁谢谢你
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 2021-12-10
  • 2020-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-20
相关资源
最近更新 更多