浅谈死锁

有段时间没写博客了,最近在基于java学多线程,同时在学校上《操作系统》这门课,可以说生活中充满了”锁”,我对锁的认识,也不单单是宿舍门上的那一把金属锁了。

锁有很多种,偏向锁,轻量级锁,重量级锁,自旋锁,重入锁…..等等,这些锁之后有空我再总结一下,之后再写。

这里我就谈谈“死锁”这个多线程中的现象。

首先有必要了解一下死锁产生的4个必要条件:

互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。

占有且等待:一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。

不可抢占:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。

循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。

       

当以上四个条件均满足,必然会造成死锁,发生死锁的进程无法进行下去,它们所持有的资源也无法释放。CPU吞吐量会下降,所以会浪费系统资源,所以说死锁是我们不想看到的情况。

 

作个不太正经的比喻,死锁“像极了爱情”,为什么这么说呢?

 

如果把女生比作资源,男生比作进程的话。

互斥:男生(进程)已经和女生(资源)确立了恋爱关系,那么其他的男生(进程)就不能再插足(访问),直到他们分手(该进程访问结束)。

占有且等待:某渣男(进程)已经和一个女生(资源)确立了恋爱关系,但因为他是渣男,所以他一个女友是不够的,以至于他一直在等一个女生恢复单身后(别的进程释放资源),再脚踏两只船(获取这个资源)。

不可抢占:朋友妻不可欺。

循环等待:一个男生(进程)和一个女生(资源)确立了恋爱关系后,这个男生不会和其他的异性朋友完全断了联系,异性朋友之一(另一个资源)可能已经和别的男生(另一个进程)确立了关系,但是“缘,妙不可言”,你懂得。

 

其实说上面这些感性的话,是想帮助大家更好理解一点,没有别的意思。但是因人而异吧,我算是比较感性的那种人哈哈。

不再扯远了,直接上一个死锁的例子吧。

public class Test14 {
   
public static String obj1 = "work1";
   
public static String obj2 = "work2";
 
   
public static void main(String[] args) {

        A a =
new A();
        B b =
new B();
        a.start();
        b.start();
    }

}


class A extends Thread {
   
@Override
   
public void run() {
        System.
out.println(this.currentThread().getName() + " is running");
       
while (true) {
           
synchronized (Test14.obj1) {
                System.
out.println("LOCK1 locked work1");
                
try {
                    Thread.sleep(
3000);//给一定的时间让B争夺obj2
               
} catch (InterruptedException e) {
                    e.printStackTrace();
                }
               
synchronized (Test14.obj2) {//产生死锁
                   
System.out.println("LOCK1 locked work2");
                }
            }

        }
    }
}


class B extends Thread {
   
@Override
   
public void run() {
        System.
out.println(this.currentThread().getName() + " is running");
       
while (true) {
           
synchronized (Test14.obj2) {
                System.
out.println("LOCK2 locked work2");
               
try {
                    Thread.sleep(
3000);
                }
catch (InterruptedException e) {
                    e.printStackTrace();
                }
               
synchronized (Test14.obj1) {
                    System.
out.println("LOCK2 locked work1");
                }
            }
        }
    }
}

执行结果

上述代码中,ALOCK1一直锁着work1不放,BLOCK2也一直锁着work2不放,所以A得不到work2,B也得不到work1,就出现了令人尴尬的死锁现象。

 

那怎么办?其实解决死锁的经典算法有银行家算法哲学家就餐算法……这里我就先不赘述,只针对这个Demo寻找解决方法。

其实大家不难发现,这个Demo中只用了synchronized的锁,其实可以用ReentranLock 中的 tryLock 避免死锁(因为有try块我就可以写finally,不管不顾先用unlock()解锁,让A不得不释放work1,B同样,这样就可以解决死锁问题了)。
上一下代码:
public class Test15 {

    public static String obj1 = "work1";

    public static String obj2 = "work2";

    public static ReentrantLock LockA = new ReentrantLock();

    public static ReentrantLock LockB = new ReentrantLock();



    public static void main(String[] args) {



        A a = new A();

        B b = new B();

        a.start();

        b.start();

    }





    static class A extends Thread {

        @Override

        public void run() {

            System.out.println(this.currentThread().getName() + " is running");

            while (true) {

                Test15.LockA.tryLock();

                System.out.println("LOCK1 locked work1");

                try {

                    Thread.sleep(3000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                } finally {

                    Test15.LockA.unlock();



                }

                Test15.LockB.tryLock();

                System.out.println("LOCK1 locked work2");



            }

        }

    }



    static class B extends Thread {

        @Override

        public void run() {

            System.out.println(this.currentThread().getName() + " is running");

            while (true) {

                Test15.LockB.tryLock();

                System.out.println("LOCK2 locked work1");

                try {

                    Thread.sleep(3000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                } finally {

                    Test15.LockB.unlock();

                   ;

                }

                Test15.LockB.tryLock();

                System.out.println("LOCK2 locked work2");



            }

        }

    }

}
执行结果

 
 
LOCK1可以获取work2,LOCK2可以获取work1,可以见得死锁问题解决了。
且学且思且凝练 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值