0
点赞
收藏
分享

微信扫一扫

线程的“死锁”,今天一下就顿悟了

西街小学的王 2022-04-27 阅读 60

我网上查到的死锁

好,如果你能看懂理解这句话,就没必要看下去了,你已经知道啥是死锁了

好,如果你还能理解这句句话,那你真没必要看下去了,你理解能力很强。再结合这些文章下面的一些代码例子。你就完全懂了

但是我没懂,或者说当时懂了,过段时间就忘了。

我理解的死锁

是的,就像 2个人拿枪互相指着,想要对方手上的枪

四个条件

为什么说这就是我理解的死锁呢?毕竟产生死锁,需要符合4个条件,那我理解的死锁,是否满足呢。下面来一一对应一下。(下面的4个条件,与上文的4个大致相似,但有细微区别,我采用《Java编程之美》里的描述)


tip:男人女人各为2个不同线程,2把抢为2个资源


一把手枪只能被一个人拿着,另外的人想要用,只能等现在正在使用的人丢了,或者从他手上抢过来。(条件1成立)

男的已经拿了一把枪,但是又提出了让女的把枪给自己的要求,而这把枪已经被女的拿着了。所以男的就等着,等的时候肯定不会把自己的枪给女方。(条件2成立)

2个人拿枪互指着,还能让对方剥夺了自己的枪?也许电影里可能有主角光环,但是两个线程可没有大鱼和小鱼的区别。(条件3成立)

很明显男的想拿女的手上的枪,女的想要拿男的手上的枪。(条件4成立)

如果你觉得2个人好像觉得条件4好像有点不好理解,那么

(假装明楼手上拿着枪指着明诚。。)

那,明诚想要明台手上的枪,明台想要明楼手上的枪,明楼想要明诚手上枪。。你看,是不是,T1->T2->T3->T1 成了个环形链呢。看他们站位也是个环。

纸上学来终觉浅,绝知此事要躬行

上代码

class LockDemo {
   //创建资源
   private static Object gunA = new Object();
   private static Object gunB = new Object();

   public static void main(String[] agrs) {
       //创建线程
       Thread threadMan = new Thread(new Runnable() {
           @Override
           public void run() {
               synchronized (gunA) {
                   System.out.println(Thread.currentThread() + "男人拿到了枪A");
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   System.out.println(Thread.currentThread() + "男人想要枪B");
                   synchronized (gunB) {
                       System.out.println(Thread.currentThread() + "男人拿到枪B");
                   }
               }
           }
       });
       Thread threadWoMan = new Thread(new Runnable() {
           @Override
           public void run() {
               synchronized (gunB) {
                   System.out.println(Thread.currentThread() + "女人拿到了枪B");
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   System.out.println(Thread.currentThread() + "女人想要枪A");
                   synchronized (gunA) {
                       System.out.println(Thread.currentThread() + "女人拿到了枪A");
                   }
               }
           }
       });
       //启动线程
       threadMan.start();
       threadWoMan.start();
   }
}

运行结果:

Thread[Thread-0,5,main]男人拿到了枪A
Thread[Thread-1,5,main]女人拿到了枪B
Thread[Thread-1,5,main]女人想要枪A
Thread[Thread-0,5,main]男人想要枪B

男女各自有一把枪指着对方,然后都试图获取对方手里的枪,但是没有后文。这就是一个死锁。

代码分析:

代码先创建了2把抢,也就是2个资源,并创建了2个线程(看结果可以知Thread-0为男,Thread-1为女)。男的先获取到一把枪后,线程sleep了1s,为的是保证女的也可以拿的枪。这样才可以继续后面的条件,这个时候,男的获得了枪A,女的获得了枪B(线程0获取了资源gunA的锁,线程1获取了资源gunB的锁)。男在拿到枪A后,视图获取枪B,而枪B已经被女的占用了,女的也视图获取枪A。显然也获取不到。于是陷入等待。也就产生了死锁。

所以\color{red}{所以}所以

2个人拿枪互相指着,想要对方手上的枪,就他妈的叫他妈的“死锁”\color{red}{2个人拿枪互相指着,想要对方手上的枪,就他妈的叫他妈的“死锁”}2个人拿枪互相指着,想要对方手上的枪,就他妈的叫他妈的“死锁”

如何打破死锁

我们来完善一下上面的场景,2个人找到了一个通往没有bug的世界的大门,但是大门紧闭,门口放了两把枪,只有同时拿到两把枪,才可以进入大门(人进去后,两把枪又回到了原来的地方)。那按照电视剧里的剧情,是不是就会发生上面这种场面呢。一人枪一把后,互补相让。

那么如何才可以避免这种僵局,让2个人都通往有bug的世界呢,其实可以一个人先拿着2把枪进去后,另一个人再去拿不就好了。

所以,打破死锁只要打破4个条件之一就行,而4个条件能打破的只有条件2“请求并持有”和条件4“环路等待”可以打破。

造成死锁的原因其实和上门例子里的场景很类似,和申请资源的顺序有很大原因。2个人如果有序的去拿枪进门。就避免了死锁的产生。代码如何体现呢?修改一下线程WoMan

 Thread threadWoMan = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (gunA) {
                    System.out.println(Thread.currentThread() + "女人拿到了抢A");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + "女人想要枪B");
                    synchronized (gunB) {
                        System.out.println(Thread.currentThread() + "女人拿到了枪B");
                    }
                }
            }
        });

运行结果

Thread[Thread-0,5,main]男人拿到了枪A
Thread[Thread-0,5,main]男人想要枪B
Thread[Thread-0,5,main]男人拿到了枪B
Thread[Thread-1,5,main]女人拿到了抢A
Thread[Thread-1,5,main]女人想要枪B
Thread[Thread-1,5,main]女人拿到了枪B

代码分析:

男女都去获取枪A。假设男先获取到枪A,则女就会被阻塞,陷入等待,而不会去获取枪B,男的获取到枪A后,再去获取枪B,也顺利的获取到了,进入了没有bug的世界。这个时候2把抢又回到了原来的地方(两把枪资源的锁被释放了)。女就可以去获取枪A再获取枪B了。

这里几个小点:

  • 1.男女两个线程start后。不一定是先start的就先获取到资源枪A
  • 2.男线程获取到枪A后,女线程不会去获取枪B,因为代码里女线程需要先获取枪A,而此时枪A被男线程获取了,女线程就陷入阻塞
  • 3.男线程获取资源枪A后,获取资源枪B的时候,不会立即释放枪A。这里有个容易误解的地方,一个线程只能同时获取一个资源么,也就是一个线程同时只能持有一把锁么,答案为:不是的。 因为锁是针对“对象”的,锁和对象是一一对应的,所以线程可以同时持有多个锁。
举报

相关推荐

0 条评论