湖州网站建设培训,电脑网站 发展移动端,关键词如何确定,iis默认网站 没有属性目录 一、死锁的三种典型场景 
1、一个线程#xff0c;一把锁 
2、两个线程#xff0c;两把锁 
3、N个线程#xff0c;M把锁 死锁#xff0c;是多线程代码中的一类经典问题。我们知道加锁是能解决线程安全问题的#xff0c;但是如果加锁的方式不当#xff0c;就可能产生死…目录 一、死锁的三种典型场景 
1、一个线程一把锁 
2、两个线程两把锁 
3、N个线程M把锁 死锁是多线程代码中的一类经典问题。我们知道加锁是能解决线程安全问题的但是如果加锁的方式不当就可能产生死锁。 一、死锁的三种典型场景 
1、一个线程一把锁 对于不可重入锁来说 一个线程没有释放锁, 然后又尝试再次加锁。 // 第一次加锁, 加锁成功 lock(); // 第二次加锁, 锁已经被占用, 阻塞等待. lock(); 按照之前对于锁的设定, 第二次加锁的时候, 就会阻塞等待. 直到第⼀次的锁被释放, 才能获取到第二个锁. 但是释放第⼀个锁也是由该线程来完成, 结果这个线程已经躺平了, 啥都不想干了, 也就无法进行解锁操作. 这时候就会死锁。 对于这种情况就是如果锁是不可重入的锁并且一个线程对这把锁加锁两次就会出现死锁。 
2、两个线程两把锁 
假设有两个线程线程1获取到锁A对A对象加锁线程2获取到锁B对B对象加锁接下来线程1尝试获取锁B线程2尝试获取锁A这时就会出现死锁。 
示例代码如下 
public class ThreadDemo1 {public static void main(String[] args) {Object A  new Object();Object B  new Object();Thread t1  new Thread(()-{synchronized (A) {//sleep一下让t2能拿到Btry {Thread.sleep(1000);}catch (InterruptedException e) {e.printStackTrace();}//在持有A的情况下对B加锁synchronized (B) {System.out.println(t1拿到了两把锁);}}});Thread t2  new Thread(()-{synchronized (B) {//sleep一下让t1能拿到Atry {Thread.sleep(1000);}catch (InterruptedException e) {e.printStackTrace();}//在持有B的情况下对A加锁synchronized (A) {System.out.println(t2拿到了两把锁);}}});//死锁一直僵持着若让t2先对A加锁再对B加锁就可避免死锁t1.start();t2.start();}
} 
这时候发生死锁线程就“卡住了”无法继续工作死锁属于程序中最严重的一类bug可见这个代码不会运行出任何结果如图 我们可以通过 jconsole 来观察这两个线程此时的状态 这两个线程都处于死锁阻塞的状态。 
如果此时约定加锁顺序让线程2也先对A加锁后对B加锁这样死锁就可以解决。 
3、N个线程M把锁 
这里用一个典型的例子来描述哲学家就餐问题。 哲学家就餐问题该问题描述的是五个哲学家共用一张圆桌分别坐在周围的五张椅子上在圆桌上有五个碗和五只筷子他们的生活方式是交替的进行思考和进餐。平时一个哲学家进行思考饥饿时便试图取用其左右最靠近他的筷子只有在他拿到两只筷子时才能进餐。进餐完毕放下筷子继续思考。 这个问题中五个哲学家就相当于五个线程五只筷子就相当于五把锁。 
在绝大多数情况下这个问题是可以正常工作的。但有一些极端的特殊情况这时会产生死锁。假如同一时刻所有的哲学家都想吃面条同时拿起了自己左边的筷子这个时候他们继续尝试拿起右边的筷子这时就拿不到了因为被别人给拿着了。此时哲学家们都等待旁边的人释放筷子但由于所有的哲学家都不想放下自己手中的筷子这时就产生死锁了谁都吃不到面条。 
如何解决死锁呢我们先来看一下产生死锁的四个必要条件 
互斥使用获取锁的过程是互斥的一个线程拿到了这把锁另一个线程也想获取就要阻塞等待。不可抢占一个线程拿到这把锁后只能主动解锁不能让别的线程强行把锁抢走。请求保持一个线程拿到了一把锁后会持有这把锁像持有锁A的情况下尝试获取锁B。循环等待/环路等待像哲学家问题一样1号哲学家等待2号哲学家释放筷子2号哲学家等待3号哲学家释放筷子…… 
解决死锁的问题核心思路就是破坏上述的必要条件只要破坏一个就可以解决死锁。 
对于互斥使用和不可抢占这是锁的最基本特性不太好破坏对于请求保持代码结构方面是否能破坏要看实际需求对于循环等待代码结构方面是最容易破坏的。 
解决上述哲学家问题死锁的情况其实有很多方案 
引入额外的筷子去掉一个线程哲学家引入计数器限制最多同时有几个哲学家进餐引入加锁顺序的规则银行家算法操作系统中的重要内容 1、2、3方案虽然不复杂但是普适性不高有时候用不了3方案普适性高。 
我们这里用一下3方案引入加锁顺序的规则来解决哲学家死锁的问题只要指定一定的规则就可以有效避免循环等待从而破坏循环等待这个必要条件。指定加锁顺序针对五只筷子进行编号约定每个哲学家获取筷子的时候一定要先拿自己左右两边编号较小的筷子拿到之后再拿编号较大的。如图假设2号哲学家先拿到1号筷子 5号哲学家拿到5号筷子后就可以进餐了吃完之后放下4号和5号筷子接着4号哲学家就可以拿到4号筷子进餐吃完之后放下3号和4号筷子接着3号哲学家就可以拿到3号筷子进餐吃完之后放下2号和3号筷子……最终1号哲学家就可以拿到1号筷子和5号筷子进餐。这样每个哲学家都可以吃到面条死锁问题也就解决了。