如上面哲学家进餐有可能发生下面的状况: java
/** * 容易由于获取锁的顺序致使死锁 */ public class LeftRightDeadLock { private final Object left = new Object(); private final Object right = new Object(); public void leftRight(){ synchronized(left){ synchronized(right){ // to do sth. } } } public void rightLeft(){ synchronized(right){ synchronized(left){ // to do sth. } } } }
public void transferMoney(Account fromAccount, Account toAccount, int money){ synchronized (fromAccount) { synchronized(toAccount){ if (fromAccount.getBalance() > money){ //余额不足 } else{ fromAccount.debit(money); toAccount.credit(money); } } } }当咱们如下面这种方式调用,就有可能出现死锁:
transferMoney(a1, a2, money); transferMoney(a2, a1, money);要解决这种问题,就得使内部以相同的顺序加锁,不管外部怎么调用。
/** * 用于当输入参数的hash值同样时使用 */ private static final Object tieLock = new Object(); public static void transferMoney(final Account fromAccount, final Account toAccount, final int money){ class Helper{ public void transfer(){ if (fromAccount.getBalance() < money){ //余额不足 } else{ fromAccount.debit(money); toAccount.credit(money); } } } int fromHash = System.identityHashCode(fromAccount); int toHash = System.identityHashCode(toAccount); //不管客户端怎么传入参数,咱们都以先锁定hash值小的,再锁定hash大的 //也能够利用业务中排序关系,如Account的编号等来比较 if (fromHash < toHash){ synchronized (fromAccount){ synchronized (toAccount) { new Helper().transfer(); } } } else if (fromHash > toHash){ synchronized (toAccount){ synchronized (fromAccount) { new Helper().transfer(); } } } else { //hash值相等, 状况很小 synchronized (tieLock) { synchronized (fromAccount) { synchronized (toAccount) { new Helper().transfer(); } } } } }在协做对象之间发生的死锁:
class Taxi { private Point location; private Point 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.notifyAvaliable(this); } } } class Dispatcher { private final Set<Taxi> taxis; private final Set<Taxi> avaliableTaxis; public Dispatcher(){ taxis = new HashSet<>(); avaliableTaxis = new HashSet<>(); } public synchronized void notifyAvaliable(Taxi taxi) { avaliableTaxis.add(taxi); } public synchronized Image getImage(){ Image image = new Image(); for (Taxi t :taxis){ image.drawMarker(t.getLocation()); } return image; } }上面的 setLocation和 getImage就有可能发生死锁现象:setLocation获取到Taxi对象锁后,在dispacher.notifiyAvaliable()时须要dispatcher锁,而getImage获取到dispacher锁后,t.getLocation要求Taxi锁。
/** * 经过公开调用来避免在相互协做的对象之间产生死锁 */ public class OpenCall { class Taxi { private Point location; private Point destination; private final Dispatcher dispatcher; public Taxi(Dispatcher dispatcher) { this.dispatcher = dispatcher; } public synchronized Point getLocation(){ return location; } public void setLocation(Point location){ boolean reachedDestination; synchronized(this){ this.location = location; reachedDestination = location.equals(destination); } if (reachedDestination){ dispatcher.notifyAvaliable(this); //这里持有dispatcher锁,但已释放taxi锁 } } } class Dispatcher { private final Set<Taxi> taxis; private final Set<Taxi> avaliableTaxis; public Dispatcher(){ taxis = new HashSet<>(); avaliableTaxis = new HashSet<>(); } public synchronized void notifyAvaliable(Taxi taxi) { avaliableTaxis.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; } } }
不吝指正。 数据库