上一篇列举了死锁的例子,就是两个线程互相竞争对方的资源,而又不释放自己的资源,导致互相死等。如下图所示:
死锁发生的条件:
1,互斥,共享资源X和Y只能被一个线程占用。
2,占用且等待,线程T1已经取得共享资源X,在等待共享资源Y的时候,不释放共享资源X。
3,不可抢占,其他线程不能强行抢占线程T1占有的资源。
4,循环等待,线程T1等待线程T2占有的资源,线程T2等待线程T1占有的资源,就是循环等待。
只要我们破坏其中一个,就可以成功避免死锁的发生。
1,互斥这个条件我们没有办法破坏,因为我们用锁就是为了互斥。
2,破坏占用且等待条件。
从理论上讲,破坏这个条件,可以一次性申请所有资源。对于转账操作来说,需要的资源有两个,一个是转出账户,另一个是转入账户。可以增加一个账本管理员,然后只允许账本管理员从文件架上拿账本,只有申请的资源都在时候,账本管理员才进行操作。
这里有一个细节需要注意,管理员如果发生申请的资源没有同时在的时候,可以有两种操作:一是直接使用while循环进行等待,二是通过wait(),notifyall()等待-通知进行操作。
3,破坏不可抢占条件。
不可抢占的核心是能够主动释放它占有的资源,这一点synchronized是做不到的。原因是synchronized申请资源的时候,如果申请不到,线程就直接进入阻塞状态了,而线程进入阻塞状态,啥都干不了,也释放不了线程占用的资源。java.util.concurrent这个包下面提供了Lock是可以轻松解决这个问题的。
4,破坏循环等待条件。
破坏这个条件可以对资源进行排序,然后按照顺序申请资源。就不是出现两个线程都申请到了对方资源而互相等待这种情况,因为资源申请的顺序已经确定了。如果线程1申请资源1,那么线程2就只能等待了。
网友评论