互斥锁避免死锁实践
发布日期:2021-07-30 05:57:26 浏览次数:5 分类:技术文章

本文共 2377 字,大约阅读时间需要 7 分钟。

死锁造成的原因

有线程T1 和线程T2 ,T1占用资源A也就是锁住了A对象synchronized(A),T2占用资源B也就是锁住了资源B对象syncrhonized。此时T1线程在去申请获取B对象的时候,T2线程还没有释放资源。T1线程就会一直等待资源B,并且也不会释放资源A.而T2也去申请资源A,就会等待资源A被释放,并且也不会释放资源B. 因此就会形成死锁。

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;        }      }    }  } }

上面的这些代码就会造成死锁。

解决死锁的办法

  1. 互斥,共享资源 X 和 Y 只能被一个线程占用;
  2. 占有且等待,线程 T1 已经取得共享资源 X,在等待共享资源Y人时候,不释放共享资源X;
  3. 不可抢占,其他线程不能强行抢占线程T1占有的资源;
  4. 循环等待,线程T1等待线程T2占有的资源,线程T2等待线程T1占有的资源,就是循环等待。

1.一次性申请多个资源

我们可以创建一个Allocator类,用这个类去申请资源。但是这个类必须是单例的。这样我们就可以避免死锁。

class Allocator {	private Allocator(){};	public static Allocator allocator = new Allocator;	public static Allocator getAllocator(){		return allocator;	}  private List als =    new ArrayList<>();  // 一次性申请所有资源  synchronized boolean apply(    Object from, Object to){    if(als.contains(from) ||         als.contains(to)){      return false;      } else {      als.add(from);      als.add(to);      }    return true;  }  // 归还资源  synchronized void free(    Object from, Object to){    als.remove(from);    als.remove(to);  }}class Account {  // actr 应该为单例  Allocator actr =getAllocator();  private int balance;  // 转账  void transfer(Account target, int amt){    // 一次性申请转出账户和转入账户,直到成功    while(!actr.apply(this, target))      ;    try{      // 锁定转出账户      synchronized(this){                      // 锁定转入账户        synchronized(target){                     if (this.balance > amt){            this.balance -= amt;            target.balance += amt;          }        }      }    } finally {      actr.free(this, target)    }  } }

2. 破坏不可抢占条件。

当线程T1无法获取全部资源的时候,就把自己的资源也释放掉。但是这里就无法使用synchronized这个关键字来做了,需要使用Lock关键字来做了。

3. 破坏循环等待条件

我们在加锁的时候,永远让锁资源按照一定的顺序。

class Account {  private int id;  private int balance;  // 转账  void transfer(Account target, int amt){    Account left = this        ①    Account right = target;    ②    if (this.id > target.id) { ③      left = target;           ④      right = this;            ⑤    }                          ⑥    // 锁定序号小的账户    synchronized(left){      // 锁定序号大的账户      synchronized(right){         if (this.balance > amt){          this.balance -= amt;          target.balance += amt;        }      }    }  } }

只要做到以上这三点的其中一个就不会出现死锁了。

转载地址:https://blog.csdn.net/u011296165/article/details/89475487 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:sring data jpa审计 @EnableJpaAuditing @EntityListeners @CreatedBy
下一篇:互斥锁 synchronized分析

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年11月22日 11时47分21秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章