java多线程——锁优化
- 引言
在java高并发环境中,“锁”是最常用的同步方法,但是激烈的锁竞争以及不合理的加锁又会导致程序的性能下降,所以锁的优化就变成了一个重要的问题,具体的锁的优化包括减小锁粒度、锁分离等。 - 减小锁的持有时间
在锁的竞争当中,单个线程对锁的持有时间将会对整个程序的性能产生较大的影响。例如,银行排队去ATM机存钱,此时ATM机就是一个竞争的资源,只有一台机器供客户存钱,如果每个客户都等到进入ATM机处才开始从钱包里面拿钱、拿银行卡,再存钱,那么就会导致机器被占用的时间变得很长,从而对整个队列的性能产生影响。但是如果客户在进入ATM机之前就已经把银行卡和钱准备好拿在手中了,等到了ATM机处直接就开始存钱,这样就能减少每一个客户对资源的占用时间,进而提高队列的性能。程序的开发也是如此,我们应当尽量减少每个线程对锁的持有时间,以减少线程间互斥的可能。如下:
public synchronized void synMethod(){
othercode1();
mutexMethod();
othercode2();
}
上述代码中,我们对整个方法做了同步控制,而方法内部只有mutexMethod()
是互斥的资源,othercode1()、othercode2()
并不需要去同步,当这两个代码块的耗时很长时,在这种同步控制方式下,会使cpu占用率变得很高,同时也会出现大量的等待线程。
但是,如果我们稍微修改一下上面的代码,就能将问题迎刃而解——对需要同步的地方加锁,而不是整个方法加锁。
public void synMethod(){
othercode1();
synchronized(this){
mutexMethod();
}
othercode2();
}
这样就能明显的提升程序的性能,提升系统的吞吐量。实际上JDK源码中有很多地方就用到了此中优化策略,比如正则表达式中的Pattern类。
减少锁的持有时间有助于降低锁冲突的可能性,进而提升系统的并发能力。
- 减小锁粒度
所谓的减小锁粒度,其实就是缩小锁定对象的范围,从而减少所冲突的可能性,提高并发能力,我认为和减小锁的持有时间是有异曲同工之处的。最为典型的应用场景就是ConcurrentHashMap
类的实现。
对于ConcurrentHashMap
其内部被细分为了若干个小的HashMap
,称为段(Segement),默认情况下被细分为16个段。对于HashMap
中最重要的方法就是put(),get()
方法,在ConcurrentHashMap
中,不是对整个HashMap
进行加锁,而是首先对需要加入的元素求其hashcode
得到它应该被放入哪一个段,然后再对段进行加锁,完成put()
方法。
注意: 减小锁粒度也会引发另一个问题,当系统需要取得全局锁的时候,会消耗比较多的资源。比如ConcurrentHashMap
中的size()
方法,即获取所有的有效表项的数量时,需要获得每一个段的锁才能返回最终的数量,这种情况下,效率是较低的。
因此,减小锁粒度应该用在不会频繁的获得全局锁的应用场景中使用。 - 读写分离锁替换独占锁
该优化方法其实也是减小锁粒度的一种特殊情况,上面的减小锁粒度是从数据结构方面来进行的,而采用读写分离锁是对系统功能点的切割。
读写分离锁在实际的开发中是很有必要的,因为系统在读数据的时候是不会破坏数据的完整性和一致性的,所以如果能允许多个线程同时读数据的话,就能节省不少的时间和降低冲突,这样读写锁就诞生了,只需要将读和写分离即可,读可以允许多个线程,而写只能一个一个的进行,读和写之间又是互斥的。具体约束如下:
在读多写少的情况下,可以使用读写锁来有效提升系统的并发能力。
- 锁粗化
一般情况下,我们要求的是尽量减少线程对锁的持有时间,但是凡事都要有一个度,不能过度,否则只会适得其反,如果频繁的对一个锁进行请求,同步,释放,就其本身而言也是一种消耗,所以我们就要适当的对其进行锁粗化——即将多次对锁的操作合并成一次来进行,从而减少对锁的请求同步操作,具体例子如下:
for(int i = 0;i < 10;i++){
synchronized(lock){
//待请求的资源
}
}
显然,在上面的代码中,锁将被请求十次,这种情况下是没有必要每一次都去请求和释放锁的,所以我们可以将锁粗化,减少请求次数,如下:
synchronized(lock){
for(int i = 0;i < 10;i++){
//待请求的资源
}
}
锁粗化之后,就只需要请求和释放一次锁,完成十次循环,明显降低了请求次数,提高并发能力。
在实际的开发当中锁粗化和减少锁的持有时间是相反的,要在具体应用场景中具体考虑,选择最为合适的方案进行优化,权衡利弊。
- 结束
以上即是对锁的一些优化建议,如果还需要更进一步的了解和学习,可以参考《高并发程序设计一书》,其中有专门针对锁优化的章节讲解,希望大家不断学习,提升自己。