zoukankan      html  css  js  c++  java
  • 第一部分:并发理论基础05->死锁了怎么办

    1.3个人互相转账

    3个人互相转账,串行

    2.账本

    1. 文件架上有转出账本+转入账本,同时拿走
    2. 文件架上只有转出账本,柜员就先把文件架上的转出账本拿到手里,同时等着另一个账本送回来。
    3. 文件架上一个账本都没有,等两个账本都回来。

    3.明细

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

    4.如何预防死锁

    出现死锁,以下4个条件

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

    破坏其中任意一个条件,就可以避免死锁发生

    1. 占有且等待,一次性申请所有资源,就不存在等待了
    2. 不可抢占条件,占用资源线程进一步申请其他资源时,申请不到,可以主动释放它占有的资源,不可抢占条件就破坏了
    3. 循环等待条件,按序申请资源。

    5.预防死锁的案例

    1. 破坏占用且等待条件
      一次性申请所有资源,就同时拿到转入账本和转出账本的概念
    
    class Allocator {
      private List<Object> 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应该为单例
      private Allocator actr;
      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)
        }
      } 
    }
    
    1. 破坏不可抢占条件
      主动释放它占用的资源,synchronized实现不了,但是Lock可以实现

    2. 破坏循环等待条件
      需要对资源进行排序,按序申请资源。

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

    6.总结

    细粒度锁,锁多个资源,注意死锁问题
    破坏死锁条件中的任意一个,就不会出现死锁

    原创:做时间的朋友
  • 相关阅读:
    解决PLSQL Developer中文横着显示的问题
    品优购_day06
    品优购_day05
    品优购_day04
    品优购_day03
    品优购_day02
    java 学习中遇到的问题(二)泛型中<? extends T>和<? super T>的区别
    java 学习中遇到的问题(一)方法调用中的值传递和引用传递
    java中的字符串比较
    自学java 第十一章持有对象
  • 原文地址:https://www.cnblogs.com/PythonOrg/p/14955101.html
Copyright © 2011-2022 走看看