java多线程之-死锁

当两个或多个线程竞争试图获取对方持有的同步锁时,它们都会处于阻塞状态,除非某个线程主动释放自己所持有的同步锁,这时,死锁就出现了。用下面这张图很好理解:
这里写图片描述
如图,线程Thread1和Thread2都有两个同步方法Operation1()、Operation2(),Operation1()中会调用Operation2().当某个时候,Thread1获取了A的对像锁,然后失去了CPU时间片,Thread2获得了CPU时间片,然后Thread2获取了B的对象锁,然后它又失去了CPU时间片,CPU时间片重新回到Thread1,这时候Thread1调用Operation2()并试图获取B的对象锁,但此时Thread2持有了B的对象锁,那么Thread1就会阻塞一直等待Thread2的对象锁释放。当CPU切换到Thread2时,它也试图获取A的对象锁,但此时Thread1持有A的对象锁,并且Thread1处于阻塞状态,一直等待着Thread2释放同步锁,因此Thread1跟Thread2就会一直等待对方释放同步锁,这时候,死锁就出现了。
具体示例代码:

class DeadLock{
    public int a = 10;

    public synchronized void add(DeadLock deadlock){
            a++;
            deadlock.decrease();
            System.out.println("deadthread01---"+a);
    }

    public synchronized void decrease(){
            a--;
            System.out.println("deadthread02---"+a);
    }
}

class DeadThread01 implements Runnable{

    private DeadLock[] deadlock;
    public DeadThread01(DeadLock ...deadlock){
        this.deadlock = deadlock;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            deadlock[0].add(deadlock[1]);
        }
    }

}

class DeadThread02 implements Runnable{

    private DeadLock[] deadlock;
    public DeadThread02(DeadLock ...deadlock){
        this.deadlock = deadlock;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            deadlock[1].add(deadlock[0]);
        }
    }

}


DeadLock deadlock1 = new DeadLock();
        DeadLock deadlock2 = new DeadLock();
        DeadThread01 thread01 = new DeadThread01(deadlock1,deadlock2);
        DeadThread02 thread02 = new DeadThread02(deadlock2,deadlock1);
        new Thread(thread01).start();
        new Thread(thread02).start();

上面代码中,DeadThread01与DeadThread02都调用了DeadLock的同步方法add()方法,当add()中开始调用同步方法decrease()时,由于两个线程都想试图获取对方的对象锁而发生死锁现象。

死锁的解决方案

死锁的出现不是很频繁,一旦出现也不容易发现,复现率也不高,因此并没有什么很好的简单方法去避免死锁,只能在平时编码的时候多加注意,避免死锁的出现。以下两点是对预防死锁的建议:

  • 锁的顺序
  • 锁超时
    1.锁的顺序:如果保证多个线程获得和释放锁的顺序相同,也就是说如果Thread1和Thread2都是先获取锁A,然后获取锁B,那么死锁就不会发生。

2.锁超时:试图为锁设置超时时间可以避免死锁的发生,也就是说给锁设置一个时间,在这个时间段内,线程如果没有获取锁,那么线程就会自动回退,释放自身持有的锁。这样就给了其他线程获取它的锁的机会,在等待随机的时间后,第一个线程又会试图获取他所需要的锁,这样就可以避免死锁的发生了。但synchronized并没有给同步锁设置时间的功能。这个时候我们就可以用Lock来同步代码了,它可以通过调用tryLock(long,TimeUnit)来设置同步的时间段。比如对上面decrease()方法进行改写成:

ReentrantLock lock = new ReentrantLock();
    public void decrease(){
            lock.lock();
            a--;
            System.out.println("deadthread02---"+a);
            lock.unlock();
    }

这里我们在需要同步的代码临界区开始处调用lock.lock(),在临界区结束处调用lock.unlock(),这样,包含在他们中间的操作就会变为原子操作。这样就不会涉及到死锁的问题。(这段同步代码也可以通过lock.tryLock()方法来设置同步时间)

好了,关于死锁的讨论就到这里了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fastsy

打赏一份隆江猪脚饭吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值