一不小心就死锁了,怎么办?

本文探讨了在并发编程中如何避免死锁的问题。通过现实世界的转账例子,介绍了细粒度锁的概念及其可能导致的死锁现象。文章详细分析了死锁的四个必要条件,并提出了破坏这些条件的预防策略,包括一次性申请所有资源、释放无法获取更多资源时已占有的资源,以及按序申请资源来避免循环等待。最后,强调了在Java中如何利用Lock接口破坏不可抢占条件。
摘要由CSDN通过智能技术生成

前言

上篇中的银行转账的例子中, 用Account.class作为互斥锁,虽然能保证并发问题,但是用户A、B、C、D,A转B,B转C是串行的,这是由于用锁Account.class将转账操作串行化了,性能就会很低,在现实生活中这两个转账操作是可以并行处理的,所以需要提升性能。

向现实世界要答案

例如古代,所有的记账都是在账本上操作的,A和B各自有两个账本,A转账给B,需要账员同时看A和B的账本都在不在,只有两个账本都在的话才能转账成功,否则就不能转账,如果只有一本账本,就不能记账,否则会出现一本记了而一本没记的情况。

将上面的转账场景放到编程中如何实现呢?其实用两把锁就可以实现了,两个账本各加一把锁。在transfer()方法内部,给this.balance加一个锁,给target也加一个锁,只有当两个锁都拿到之后才执行this.balance -= amt; target.balance += amt;操作。

class Account {
   
  private int balance;
  // 转账
  void transfer(Account target, int amt){
   
    // 锁定转出账户
    synchronized(this) {
                 
      // 锁定转入账户
      synchronized(target) {
              
        if (this.balance > amt) {
   
          this.balance -= amt;
          target.balance += amt;
        }
      }
    }
  } 
}

在这里插入图片描述

没有免费的午餐

相对于Account.class作为互斥锁,上述的例子锁定的范围就很小了,这样的锁叫做细粒度锁,使用细粒度锁可以提高并发度,是优化性能的一个重要手段。

使用细粒度的锁是有代价的,这个代价就是可能会导致死锁。

例如古代有A和B两个用户,A向B转帐,找记账员,单此时B向A也要转账(假设他们两个不认识,只知道用户唯一名),于是A和B都向柜员要账本,A拿到A的账本,B拿到B的账本,而此时A要等B归还账本,B要等A归还账本,这样就会无限制等下去,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值