【面试题】死锁

背景

今天参加了一家公司的面试,问到了死锁的问题。想到死锁的四个充要条件也不记得了,有点慌。

正文

什么是死锁

用我自己的话说,就是不同的线程占据着不同的资源,想要访问对方,但是对自己占有的资源不放手。举个例子,家里有两个小孩,各自有一个玩具,有一天他们打起来了,问了下说是A想玩B的玩具,B想玩A的玩具,但是他们俩都表示,要对方先给,不给就不会把自己的玩具拿出来。虽然有很多不一样的地方,但是大体上的意思就是这样,如果这些条件不变的话,他们永远就再争吵。大概就是这样:

如果两个孩子愿意放手自己手里的玩具,或者没有刚好到了持有并去获取的状态,也不会出现这样的情况。这就要说明下死锁的四个条件了,这四个条件必须全部满足,死锁才能成立,破除其中的一个都会破坏死锁。

互斥条件、不可剥夺、请求与保持、循环等待

复习了下,但是就不展开来说了。

但是在代码里面,怎么能出现死锁呢?我想了想,脑袋一拍写了下面这个代码


public class DeathLock {
    int c = 0;
    int d = 0;
    public DeathLock(){}
    public static void main(String[] args) throws InterruptedException {
        DeathLock deathLock = new DeathLock();
        new Thread(() -> {
            try {
                deathLock.run();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                deathLock.run();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
    public void run() throws InterruptedException {
        for(int i = 0; i <10;i++){
            doingA();
            doingB();

        }
    }
    public synchronized void doingA() throws InterruptedException {
        c++;
        Thread.sleep(3000);
        System.out.println(Thread.currentThread()+":"+ c);
    }
    public  synchronized void doingB() throws InterruptedException {
        d++;
        Thread.sleep(3000);
        System.out.println(Thread.currentThread()+":"+ d);
    }
}

耻辱啊。居然能写出这样的代码。这明明就是顺序执行

很明显缺少了循环等待的条件,那怎么做呢?

加进来,拍脑袋

private  int flag = 0;
    public  Object o1=new Object();
    public  Object o2=new Object();
    public void setFlag(int num){
        this.flag=num;
    }
    @Override
    public void run() {
        if(flag == 0){
            synchronized (o1){
                System.out.println("o1"+Thread.currentThread().getName());
                synchronized (o2){
                    System.out.println("o2"+Thread.currentThread().getName());
                }
            }
        }
        if(flag == 1){
            synchronized (o2){
                System.out.println("o2"+Thread.currentThread().getName());
                synchronized (o1){
                    System.out.println("o1"+Thread.currentThread().getName());
                }
            }
        }
    }

    public static void main(String[] args) {
        DeathLock2 deathLocka = new DeathLock2();
        DeathLock2 deathLockb = new DeathLock2();
        deathLockb.flag=1;
        Thread thread= new Thread(deathLocka,"threadA");
        Thread thread2= new Thread(deathLockb,"threadB");
        thread.start();
        thread2.start();
    }

但是貌似也没发生死锁,我明明对两个不同的对象都加了锁,分别走了不同的路径,相互争夺资源呀。

仔细想想,我创建了thread和thread2分别运行,在thread运行的时候,对deathLocka中的o1进行加锁,然后thread2运行的时候,对deathLockb中的o2进行加锁操作,再往后,在thread在o1还在加锁的状态下去尝试获取o2的锁,thread2也在加锁的状态下去获取o1的锁,看起来好像没问题。但是这里的deathLocka和deathLockb不是同一个对象啊兄弟。锁了deathLocka中的o1,但是没有锁到deathLockb中的o1,那不是白锁了吗。。。

这样我把o1,o2设置为静态对象,这样它就是线程共享的了。试试看果然发生了死锁。


public class DeathLock2 implements Runnable{
    private  int flag = 0;
    public  Object o1=new Object();
    public  Object o2=new Object();
    public void setFlag(int num){
        this.flag=num;
    }
    @Override
    public void run() {
        if(flag == 0){
            synchronized (o1){
                System.out.println("o1"+Thread.currentThread().getName());
                synchronized (o2){
                    System.out.println("o2"+Thread.currentThread().getName());
                }
            }
        }
        if(flag == 1){
            synchronized (o2){
                System.out.println("o2"+Thread.currentThread().getName());
                synchronized (o1){
                    System.out.println("o1"+Thread.currentThread().getName());
                }
            }
        }
    }

    public static void main(String[] args) {
        DeathLock2 deathLocka = new DeathLock2();
        DeathLock2 deathLockb = new DeathLock2();
        deathLockb.setFlag(1);
        Thread thread= new Thread(deathLocka,"threadA");
        Thread thread2= new Thread(deathLockb,"threadB");
        thread.start();
        thread2.start();
    }
}

死锁是多线程中的一个重要问题,java中各种加锁的情况使用不当都可能造成死锁。

结束

周末了就早点休息,明天再写。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值