闽公网安备 35020302035485号
public class TansferAccount{
private Integer balance;
public void transfer(TansferAccount target, Integer transferMoney){
synchronized(TansferAccount.class){
if(this.balance >= transferMoney){
this.balance -= transferMoney;
target.balance += transferMoney;
}
}
}
}
这种方式确实解决了转账操作的并发问题,但是这种方式在高并发环境下真的可取吗?试想,如果我们在高并发环境下使用上述代码来处理转账操作,因为 TansferAccount.class 对象是 JVM 在加载 TansferAccount 类的时候创建的,所有的 TansferAccount 实例对象都会共享一个 TansferAccount.class 对象。也就是说,所有 TansferAccount 实例对象执行 transfer()方法时,都是互斥的!!换句话说,所有的转账操作都是串行的!!
public class TansferAccount{
//账户的余额
private Integer balance;
//转账操作
public void transfer(TansferAccount target, Integer transferMoney){
//对转出账户加锁
synchronized(this){
//对转入账户加锁
synchronized(target){
if(this.balance >= transferMoney){
this.balance -= transferMoney;
target.balance += transferMoney;
}
}
}
}
}
此时,上面的代码看上去没啥问题,但真的是这样吗? 我也希望程序是完美的,但是往往却不是我们想的那样啊!没错,上面的程序会出现 死锁, 为什么会出现死锁啊? 接下来,我们就开始分析一波。public class TansferAccount{
private Lock thisLock = new ReentrantLock();
private Lock targetLock = new ReentrantLock();
//账户的余额
private Integer balance;
//转账操作
public void transfer(TansferAccount target, Integer transferMoney){
boolean isThisLock = thisLock.tryLock();
if(isThisLock){
try{
boolean isTargetLock = targetLock.tryLock();
if(isTargetLock){
try{
if(this.balance >= transferMoney){
this.balance -= transferMoney;
target.balance += transferMoney;
}
}finally{
targetLock.unlock
}
}
}finally{
thisLock.unlock();
}
}
}
}
其中 Lock 中有两个 tryLock 方法,分别如下所示。tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回 true,如果获取失败(即锁已被其他线程获取),则返回 false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
public class ResourcesRequester{
//存放申请资源的集合
private List<Object> resources = new ArrayList<Object>();
//一次申请所有的资源
public synchronized boolean applyResources(Object source, Object target){
if(resources.contains(source) || resources.contains(target)){
return false;
}
resources.add(source);
resources.add(targer);
return true;
}
//释放资源
public synchronized void releaseResources(Object source, Object target){
resources.remove(source);
resources.remove(target);
}
}
此时,TansferAccount 类的代码如下所示。public class TansferAccount{
//账户的余额
private Integer balance;
//ResourcesRequester类的单例对象
private ResourcesRequester requester;
//转账操作
public void transfer(TansferAccount target, Integer transferMoney){
//自旋申请转出账户和转入账户,直到成功
while(!requester.applyResources(this, target)){
//循环体为空
;
}
try{
//对转出账户加锁
synchronized(this){
//对转入账户加锁
synchronized(target){
if(this.balance >= transferMoney){
this.balance -= transferMoney;
target.balance += transferMoney;
}
}
}
}finally{
//最后释放账户资源
requester.releaseResources(this, target);
}
}
}
破坏循环等待条件public class TansferAccount{
//账户的id
private Integer id;
//账户的余额
private Integer balance;
//转账操作
public void transfer(TansferAccount target, Integer transferMoney){
TansferAccount beforeAccount = this;
TansferAccount afterAccount = target;
if(this.id > target.id){
beforeAccount = target;
afterAccount = this;
}
//对转出账户加锁
synchronized(beforeAccount){
//对转入账户加锁
synchronized(afterAccount){
if(this.balance >= transferMoney){
this.balance -= transferMoney;
target.balance += transferMoney;
}
}
}
}
}
总结