发生死锁的田间以及解决办法

死锁的场景:多线程执行,线程1:账户A转账给账户B;线程2:账户B转账给账户A;线程1和线程2同时转账时,就可能会发生 死锁:
         线程1:new TransferAccount(fromAccount,toAccount,1)       
         线程2:new TransferAccount(toAccount,fromAccount,2) 
         如果执行顺序不恰当,那么线程1可能获得fromAccount的锁,并且等待toAccount的锁;然而此时线程2拥有toAccount的锁,并正在等待fromAccount的锁。

转账死锁的避免:
死锁一旦产生是没有办法解决的,只能重启应用. 所以解决死锁的最好办法就是避免死锁,如何避免死锁,那就要从产生死锁的条件入手:

互斥:共享资源X和Y只能被一个线程占用
占有且等待:线程T1已经取得共享资源X,在等待共享资源Y的时候,不释放共享资源X
不可抢占:其他线程不能强行抢占T1占有的资源
循环等待:线程T1等待线程T2占有的资源,线程T2等待线程T1占有的资源,就是循环等待
四个添加同时满足就会产生死锁,只要能破坏掉有一个条件,死锁就不会产生。共享资源是没有办法破坏,也就是互斥是没有办法解决,锁的目的就是为了互斥.

占有且等待: 一次性申请所有的资源就可以解决
不可抢占: 占用部分资源后获取不到后续资源就释放掉前面获取的资源,就可以解决
循环等待: 按照序号申请资源来预防,也就是说给每个资源标记一个序号,没次加锁的时候都先获取资源序号小的,这样有顺序就不会出现循环等待
2.1 破坏“占用且等待”
只需要同时申请资源就可以,同时申请这个操作是一个临界区,需要一个Java类来管理这个临界区,也就是定义一个角色,这个角色的两个重要功能就是同时申请资源apply()和同时释放资源free(),并且这个类是单例的.其实本质就是设置一个管理员,只有管理员有权限去分配资源,其他普通用户只能去管理员那取资源,一个人操作就不会产生死锁了.

 

2.2 破坏不可抢占条件
这个的核心是释放掉已占有的资源,这个synchronized是做不到,因为synchronized申请资源的时候如果申请不到就直接进入阻塞,阻塞状态啥也干不了.

这个时候就需要java.util.concurrent包下提供的Lock,这个等学到的时候再总结.

 

2.3 破坏循环等待条件
确定一个加锁的顺序;按照这个顺序来获得锁,就不会出现死锁的情况。

posted @ 2020-04-13 10:21  dousil  阅读(28)  评论(0)    收藏  举报