第一部分:并发理论基础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
不能用自己家的锁,保护别人家的大门一样
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;
}
}
}
}
5.总结
理清多个资源的关系
资源之间没关系,很好处理。每个资源一把锁
资源之间有关系,选择粒度更大的锁,锁要覆盖所有相关的资源
原子性
本质其实是不可分割,多个资源一致性要求。中间状态对外不可见
不能用可变对象做锁
原创:做时间的朋友