死锁

2018-06-11  本文已影响0人  墨平语凡

死锁分析

void transfer(Account from, Account to, int amount){
          from.setAmount(from.getAmount()-amount);
          to.setAmount(to.getAmount()+amount);
}

问题:
比如两个人都从fromto转了5块钱,第一个人.getAount()得到10块钱,还没来得及-amout,第二个人.getAmount()得到也是10块钱,然后两个人都减了5块钱,都认为减完以后是5块钱,就都执行各自的from.setAmout(),这样账户里还有5块钱,但明明转了两次5块,余额应该为0结果却为5

加锁:

void transfer(Account from, Account to, int amount){
      synchronized(from){
          synchronized(to){
             from.setAmount(from.getAmount()-amount);
             to.setAmount(to.getAmount()+amount);
        }
   }       
}

fromto都锁住,这样在第一个人转完之前第二个人是进步去的,就不能拿到,synchronized锁住的是对象,第一个锁住了from,第二个锁住了to。对于同一个账户,同一个from,第一个人进来以后,第二个人就进不来了。

会发生死锁

  from.setAmount(from.getAmount()-amount);

from.getAmount()可以断开,from.getAmount()-amount可以断开,rom.setAmount(from.getAmount()-amount);也可以断开,当加上synchronized就安全

void transfer(Account from, Account to, int amount){
      synchronized(from){
         ...
        }      
}
void transfer(Account from, Account to, int amount){
      synchronized(from){
         synchronized(to){
              ...
            }
        }      
}

死锁条件,必须同时满足

互斥等待:有一段代码块或一个操作,同时只能有一个人做,没抢到锁的人必须等待第一个人做完。就是必须有锁的存在
抢占和等待(hold and wait): 抢到了锁,不做事情,却等待另外一个锁
循环等待:拿了a的锁却等b,另外一个却拿到了b的锁来等a
无法剥夺的等待:一直等待锁

死锁防止:

破除互斥等待 -> 一般无法破除

破除hold and wait -> 一次性获取所有资源

例如

void transfer(Account from, Account to, int amount){
      synchronized(from){
         synchronized(to){
              ...
            }
        }      
}

是分开加锁的,如果同时锁住fromto就可以,但大部分语言都不支持同时锁两个对象。对代码做修改,让fromto暴露锁,锁是针对amount的,from可以getAmountLock, to也可以getAmountLock这样就获得了两个锁的object,对锁的object可以用其他方法锁住他们,锁的时候可以带上很短的超时,先把from锁住,to带一个非常短的超时去锁,如果锁不住,就把from释放,过段时间重新尝试将两者都锁住。

破除循环等待 -> 按顺序获取资源

根据AccountID来加锁,谁的AccountID小谁先加锁就不会产生循环等待

破除无法剥夺的等待 ->加入超时

上一篇下一篇

猜你喜欢

热点阅读