不同线程,获得获得相同多个锁的顺序不同导致死锁:
public class LeftRightDeadlock { private final Object left = new Object(); private final Object right = new Object(); public void leftRight() { synchronized (left) { synchronized (right) { doSomething(); } } } public void rightLeft() { synchronized (right) { synchronized (left) { doSomething(); } } } }
根据参数来决定locking顺序同样有死锁风险:
public void transferMoney(Account from, Account to, double amount) { synchronized (from) { synchronized (to) { doSomething(); } } }
解决办法:根据参数来推导出固定的locking顺序:
priate static final Object tieLock = new Object(); public void transferMoney(Account from, Account to, double amount) { long fromHash = System.identityHashCode(from); long toHash = System.identityHashCode(to); if (fromHash < toHash) { synchronized (from) { synchronized (to) { doSomething(); } } } else if (toHash < fromHash) { synchronized (to) { synchronized (from) { doSomething(); } } } else { synchronized (tieLock) { // 当出现hash相同的情况时,全部都穿行到tieLock下执行 synchronized (from) { synchronized (to) { doSomething(); } } } } }
因为多个对象的协作导致的比较隐蔽的死锁:
class Taxi { private final Dispatcher dispatcher; public synchronized Point getLocation() { // ... } public synchronized void setLocation(Point location) { this.location = location; // alien method dispatcher.notifyAvailable(this); } } class Dispatcher { private final Set<Taxi> taxis; public synchronized void notifyAvailable(Taxi taxi) { // ... } public synchronized Image getImage() { Image image = new Image(); for (Taxi taxi : taxis) { // alien method image.drawMarker(taxi.getLocation()); } return image; } }
用Open calls改造,
class Taxi { private final Dispatcher dispatcher; public synchronized Point getLocation() { // ... } public void setLocation(Point location) { synchronized (this) { this.location = location; } // alien method dispatcher.notifyAvailable(this); } } class Dispatcher { private final Set<Taxi> taxis; public synchronized void notifyAvailable(Taxi taxi) { // ... } public Image getImage() { Set<Taxi> copy; // 限制了在调用alien方法时,本身不持有锁 synchronized (this) { copy = new HashSet<>(taxis); } Image image = new Image(); for (Taxi taxi : copy) { // alien method image.drawMarker(taxi.getLocation()); } return image; } }