Java并发4:互斥锁(下)


Java并发4:互斥锁(下)

受保护资源和锁之间合理的关联关系应该是 N:1 的关系,即可以用一把锁来保护多个资源,但不能多把锁保护一个资源。

要保护多个资源,首先要区分这些资源是否存在关联关系。

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

有一用户账户类Account。

对于用户账户,有账号,密码,余额等属性。

密码和余额是没有关联关系的,这样就可以建两把锁,来保护密码和余额。不同的资源用不同的锁来保护。

当然也可以用一把锁来保护,比如直接用用户对象this保护.

但这样问题就是性能太差,对密码和余额操作都需要共享一把锁。

所以还是对不同的资源采取不同的锁进行精细化管理,能够提升性能,即细粒度锁。

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

比如A账户向B账户转账,这样要同时锁定A&B两个资源。

保证锁能覆盖所有的保护资源。

  • 传入同一个锁进行转账
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;
      }
    }
  }
}

这个办法要求在创建 Account 对象的时候必须传入同一个对象,如果创建 Account 对象时,传入的 lock 不是同一个对象,就会出现问题。

在真实的项目场景中,创建 Account 对象的代码很可能分散在多个工程中,传入共享的 lock实际上很难。

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

此举会出现性能问题,因为所有用户的Account中的所有操作都会用同一个锁。

思考

用两把不同的锁来分别保护账户余额、账户密码,创建锁的时候:

final Object xxxLock
如果账户余额用``` this.balance``` 作为互斥锁,账户密码用``` this.password ```作为互斥锁,是否可以? 不可以。不能用可变对象做锁。 ```balance```是```Integer```,```password```是```String```,都是不可变对象,一但对他们进行赋值就会变成新的对象,加的锁就失效了。 核心问题有两点: + 一个是锁有可能会变化:如果锁发生变化,就意味着失去了互斥功能。 + 一个是 ```Integer``` 和 ```String``` 类型的对象不适合做锁:```Boolean```、 ```Integer``` 和 ```String``` 类型的对象在 JVM 里可能被重用。重用意味着锁可能被其他代码使用,如果其他代码 ```synchronized(锁)```,且不释放,那程序就永远拿不到锁,这是隐藏的风险。 **锁应是私有的、不可变的、不可重用的。** ### 别人的总结 >是否可以在```Account```中添加一个静态```object```,通过锁这个```object```来实现一个锁保护多个资源,如下: > >```java >class Account { > private final static Object lock = new Object(); > private int balance; > // 转账 > void transfer(Account target, int amt){ > synchronized(lock) { > if (this.balance > amt) { > this.balance -= amt; > target.balance += amt; > } > } > } >}

——yuc

note:这样的话所有用户转账操作用的是同一把锁。


文章作者: Wendell
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Wendell !
评论
  目录