# 《并发设计模式》第10章-保护性暂挂模式-解决交易过程性能与死锁问题
作者:冰河
星球:http://m6z.cn/6aeFbs (opens new window)
博客:https://binghe.gitcode.host (opens new window)
文章汇总:https://binghe.gitcode.host/md/all/all.html (opens new window)
源码获取地址:https://t.zsxq.com/0dhvFs5oR (opens new window)
沉淀,成长,突破,帮助他人,成就自我。
- 本章难度:★★☆☆☆
- 本章重点:掌握多线程下优化锁粒度与加锁的方式,掌握死锁的核心原理、发生死锁的必要条件,以及如何预防死锁的问题,结合自身实际项目场景思考加锁与性能问题,并将本章学到的知识灵活应用到自身实际项目中。
大家好,我是冰河~~
在多线程环境下,加锁并不是想象的那么简单,不加锁,会有线程安全问题,错误的加锁方式,不一定能够解决线程安全问题,还可能引起性能与死锁问题。
# 一、故事背景
老王虽然给小菜分不同的业务关系场景讲明白了交易过程中存在的线程安全问题,也讲解了如何使用正确的方式加锁。但是老王最后说了一句:让小菜回去思考下,还有没有什么优化的加锁方式。于是,小菜走出会议室后便记下了这个问题。下班回到家后,小菜就尝试去优化这个加锁方式,自己觉得优化好了。于是又拿给老王看,结果。。。
哎,小菜啊小菜,你可长点心吧。。。
# 二、事与愿违
这天,小菜的心情挺好,因为他觉得自己正确的优化了加锁的方式,高高兴兴的来到公司,想着让老王为自己看看。当他看到老王进来时,便站起身说到:“老大,早,你昨天不是说有更好的加锁方式吗?我回去后优化了下加锁方式,你帮我看看对吗?”。
“好,优化好了吗?我看看”,于是老王走到了小菜的工位旁,看了下小菜写的代码。随即皱了下眉头,说道:“还是有问题,你这段代码很容易引起死锁的问题”。
“啊?是吗?不会吧?”,小菜满脸的疑惑问到。
“这样吧,我们还是去会议室,我给你讲讲是怎么回事。”
“好的”,就这样,二人又走进来会议室。
# 三、为何需要优化加锁方式?
“昨天我们在讲加锁的安全性问题时,最后写了一段代码,这段代码虽然能够正确的加锁,但是存在着性能问题”,老王边说,边打开了昨天写的TansferAccount类,如下所示。
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;
}
}
}
}
2
3
4
5
6
7
8
9
10
11
这种方式确实解决了转账操作的并发问题,但是这种方式在高并发环境下真的可取吗?试想,如果我们在高并发环境下使用上述代码来处理转账操作,因为TansferAccount.class对象是JVM在加载TansferAccount类的时候创建的,所有的TansferAccount实例对象都会共享一个TansferAccount.class对象。也就是说,所有TansferAccount实例对象执行transfer()方法时,都是互斥的!!换句话说,所有的转账操作都是串行的!!
如果所有的转账操作都是串行执行的话,造成的后果就是:账户A为账户B转账完成后,才能进行账户C为账户D的转账操作。如果全世界的网民一起执行转账操作的话,这些转账操作都串行执行,那么,程序的性能是完全无法接受的!!!
其实,账户A为账户B转账的操作和账户C为账户D转账的操作完全可以并行执行。所以,我们必须优化加锁方式,提升程序的性能!!
“噢,原来如此,难怪老大你问我有没有优化的加锁方式了,这里我听明白了”,小菜高兴的说。
“好,我们继续”,老王说。
# 四、初步优化加锁方式
既然直接TansferAccount.class对程序加锁在高并发环境下不可取,那么,我们到底应该怎么做呢?!
仔细分析下上面的代码业务,上述代码的转账操作中,涉及到转出账户this和转入账户target,所以,我们可以分别对转出账户this和转入账户target加锁,只有两个账户加锁都成功时,才执行转账操作。这样就能够做到账户A为账户B转账的操作和账户C为账户D转账的操作完全可以并行执行。
我们可以将优化后的逻辑用一张图表示,于是老王便画出了一张图,如图10-1所示。
随后,老王又说到:“其实这张图表示的含义跟你写的代码一样,我们看看你写的代码”,老王对小菜说。
“是吗?”,小菜有点疑惑,“那我这代码不是优化了吗?”。
“是有问题的,我们来分析下”,说着,老王打开了小菜写的TansferAccount类。
# 查看全文
加入冰河技术 (opens new window)知识星球,解锁完整技术文章与完整代码