第一部分:并发理论基础04->互斥锁(下),如何用一把锁保护多个资源

1.一把锁保护多个资源

受保护资源和锁的关系是N:1

2.保护没有关联关系的多个资源

银行业务中针对账户余额的取款操作
银行业务中针对账户密码的更改操作
为账户余额和密码修改分配不同的锁来解决并发问题

代码,两把锁ballLock,pwLock分别保护不同的资源


class Account {
  // 锁:保护账户余额
  private final Object balLock
    = new Object();
  // 账户余额  
  private Integer balance;
  // 锁:保护账户密码
  private final Object pwLock
    = new Object();
  // 账户密码
  private String password;

  // 取款
  void withdraw(Integer amt) {
    synchronized(balLock) {
      if (this.balance > amt){
        this.balance -= amt;
      }
    }
  } 
  // 查看余额
  Integer getBalance() {
    synchronized(balLock) {
      return balance;
    }
  }

  // 更改密码
  void updatePassword(String pw){
    synchronized(pwLock) {
      this.password = pw;
    }
  } 
  // 查看密码
  String getPassword() {
    synchronized(pwLock) {
      return password;
    }
  }
}

用不同的锁保护资源进行精细化管理,能够提升性能,这叫做细粒度锁

3.保护有关联关系的多个资源

例如转账操作,账户A减少100,账户B增加100
image

不能用自己家的锁,保护别人家的大门一样

4.使用锁的正确姿势

一把锁保护多个资源
很简单,A,B两个账户用的是一把锁就好了

如何一把锁,什么套路?
(1)2个Account对象都持有一个唯一的对象,这个对象再Account生成时传入


class Account {
  private Object lock;
  private int balance;
  private Account();
  // 创建Account时传入同一个lock对象
  public Account(Object lock) {
    this.lock = lock;
  } 
  // 转账
  void transfer(Account target, int amt){
    // 此处检查所有对象共享的锁
    synchronized(lock) {
      if (this.balance > amt) {
        this.balance -= amt;
        target.balance += amt;
      }
    }
  }
}

(2)对Account.class类文件加锁


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

image

5.总结

理清多个资源的关系
资源之间没关系,很好处理。每个资源一把锁
资源之间有关系,选择粒度更大的锁,锁要覆盖所有相关的资源

原子性
本质其实是不可分割,多个资源一致性要求。中间状态对外不可见
不能用可变对象做锁

posted @ 2021-06-25 16:15  SpecialSpeculator  阅读(77)  评论(0编辑  收藏  举报