死锁

作者: 墨平语凡 | 来源:发表于2018-06-11 19:39 被阅读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){
             ...
            }      
    }
    
    • synchronized(from) -> 别的线程在等待from
      不利的情况:自己刚锁完,就有其他人等待这个锁
    void transfer(Account from, Account to, int amount){
          synchronized(from){
             synchronized(to){
                  ...
                }
            }      
    }
    
    • synchronized(to) -> 别的线程已经锁住了to
      不利的情况:别人锁了to,自己再用的时候要等待

    • 可能死锁:transfer(a,b,100)transfer(b,a,100)同时进行
      左边抢走了a的锁,右边抢走了b的锁
      左边要获取的b锁已经被右边抢走,右边要获取的a锁已经被左边抢走

    死锁条件,必须同时满足

    互斥等待:有一段代码块或一个操作,同时只能有一个人做,没抢到锁的人必须等待第一个人做完。就是必须有锁的存在
    抢占和等待(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小谁先加锁就不会产生循环等待

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

    相关文章

      网友评论

          本文标题:死锁

          本文链接:https://www.haomeiwen.com/subject/huoheftx.html