简体   繁体   English

协作对象之间的死锁

[英]Deadlock between Cooperating objects

While going through the Java Concurrency in Practice I came across the below code Deadlock , which demonstrated how a deadlock can occur between cooperating objects . Java Concurrency in Practice我遇到了下面的死锁代码,它演示了如何在cooperating objects之间发生deadlock If one thread calls getImage() and at the same time another calls setLocation() it can lead to deadlock due to lock ordering .如果一个线程调用getImage()并且同时另一个线程调用setLocation()它可能会由于lock ordering而导致死锁。 To solve this we use Open calls No Deadlock below .为了解决这个问题,我们在下面使用Open calls No Deadlock My doubt is inside setLocation() in No Deadlock why are we doing synchronized(this) again inside the already synchronized method ?我的疑问是在No Deadlock 中的setLocation()内部,为什么我们在已经synchronized方法中再次执行synchronized(this) Isn't the synchronized method already synchronized on this ?是不是synchronized已方法synchronizedthis How are we preventing the deadlock using the 2nd example?我们如何使用第二个示例防止死锁?

DeadLock僵局

class Taxi {
        @GuardedBy("this")
        private Point location, destination;
        private final Dispatcher dispatcher;

        public Taxi(Dispatcher dispatcher) {
            this.dispatcher = dispatcher;
        }

        public synchronized Point getLocation() {
            return location;
        }

        public synchronized void setLocation(Point location) {
            this.location = location;
            if (location.equals(destination))
                dispatcher.notifyAvailable(this);
        }
    }

    class Dispatcher {
        @GuardedBy("this")
        private final Set<Taxi> taxis;
        @GuardedBy("this")
        private final Set<Taxi> availableTaxis;

        public Dispatcher() {
            taxis = new HashSet<Taxi>();
            availableTaxis = new HashSet<Taxi>();
        }

        public synchronized void notifyAvailable(Taxi taxi) {
            availableTaxis.add(taxi);
        }

        public synchronized Image getImage() {
            Image image = new Image();
            for (Taxi t : taxis)
                image.drawMarker(t.getLocation());
            return image;
        }
    }

No Deadlock没有死锁

class Taxi {
        @GuardedBy("this")
        private Point location, destination;
        private final Dispatcher dispatcher;

        public synchronized Point getLocation() {
            return location;
        }

        public synchronized void setLocation(Point location) {
            boolean reachedDestination;
            synchronized (this) {
                this.location = location;
                reachedDestination = location.equals(destination);
            }
            if (reachedDestination)
                dispatcher.notifyAvailable(this);
        }
    }

    class Dispatcher {
        @GuardedBy("this")
        private final Set<Taxi> taxis;
        @GuardedBy("this")
        private final Set<Taxi> availableTaxis;

        public synchronized void notifyAvailable(Taxi taxi) {
            availableTaxis.add(taxi);
        }

        public Image getImage() {
            Set<Taxi> copy;
            synchronized (this) {
                copy = new HashSet<Taxi>(taxis);
            }
            Image image = new Image();
            for (Taxi t : copy)
                image.drawMarker(t.getLocation());
            return image;
        }
    }

There is no deadlock in second because getImage not synchronized, so when calling getLocation no lock is held.第二次没有死锁,因为 getImage 没有同步,所以在调用 getLocation 时没有锁定。 You're right about the synchronized(this) inside setLocation, it serves no purpose.您对 setLocation 中的 synchronized(this) 是正确的,它没有任何用处。

The Taxi.setLocation method in the "No Deadlock" code listing shouldn't be synchronized . “无死锁”代码清单中的Taxi.setLocation方法不应synchronized

The online errata page reads:在线勘误页面如下:

p.214 In Listing 10.6, Taxi.setLocation should not be a synchronized method. p.214 在代码清单 10.6 中, Taxi.setLocation不应该是一个同步方法。 (The synchronized block in its body is correct, however.) (Fixed in 6th printing.) (然而,其主体中的同步块是正确的。)(在第 6 次印刷中修复。)

In the deadlock-prone code, when a thread calls Taxi.setLocation , it first acquires the Taxi lock.在容易死锁的代码中,当一个线程调用Taxi.setLocation ,它首先获取Taxi锁。 And while holding the Taxi lock , it proceeds to get the Dispatcher lock.在持有Taxi锁的同时,它继续获取Dispatcher锁。

Taxi.setLocation

┌----lock Taxi
|  ┌-lock Dispatcher
│  |
|  └-unlock Dispatcher
└----unlock Taxi

This pattern is similar to the LeftRightDeadlock example with nested lock acquisition.此模式类似于具有嵌套锁获取的LeftRightDeadlock示例。

// Warning: deadlock-prone!
public void leftRight() {
  synchronized (left) {
    synchronized (right) {
      doSomething()
    }
  }
}

In the revised version, note the Taxi lock is released before acquiring the Dispatcher lock .在修改后的版本中,注意在获取Dispatcher锁之前释放Taxi

Taxi.setLocation

┌----lock Taxi
└----unlock Taxi

┌----lock Dispatcher
└----unlock Dispatcher

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM