如上面哲學家進餐有可能發生下面的狀況: 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; } } }
不吝指正。 數據庫