java 锁保护_JAVA并发实践-04 | 互斥锁(下):如何用一把锁保护多个资源?

```java

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;

}

}

}

```

## 总结

原子性”的本质是什么?其实不是不可分割,不可分割只是外在表现,其本质是多个资源间有一致性的要求,操作的中间状态对外不可见。例如,在 32 位的机器上写 long 型变量有中间状态(只写了 64 位中的 32 位),在银行转账的操作中也有中间状态(账户 A 减少了 100,账户 B 还没来得及发生变化)。

所以解决原子性问题,是要保证中间状态对外不可见。

## 课后思考

在第一个示例程序里,我们用了两把不同的锁来分别保护账户余额、账户密码,创建锁的时候,我们用的是:private final Object xxxLock = new Object();,如果账户余额用 this.balance 作为互斥锁,账户密码用 this.password 作为互斥锁,你觉得是否可以呢?

## 精彩回答

> 不可以。因为balance为integer对象,当值被修改相当于换锁,还有integer有缓存-128到127,相当于同一个对象。

> 用this.balance 和this.password 都不行。在同一个账户多线程访问时候,A线程取款进行this.balance-=amt;时候此时this.balance对应的值已经发生变换,线程B再次取款时拿到的balance对应的值并不是A线程中的,也就是说不能把可变的对象当成一把锁。this.password 虽然说是String修饰但也会改变,所以也不行。老师所讲的例子中的两个Object无论多次访问过程中都未发生变化,不能用可变对象做锁

```java

//是否可以在Account中添加一个静态object,通过锁这个object来实现一个锁保护多个资源,如下:

class Account {

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

}

}

}

}

```

> 这种方式比锁class更安全,因为这个缺是私有的。有些最佳实践要求必须这样做。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值