锁的性能和优化

###避免死锁
死锁满足的条件:

  1. 互斥条件:一个资源每次只能被一个线程使用。

  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已经获得的资源保持不放

  3. 不剥夺条件:进程已经获得的资源,在未使用之前,不能强行剥夺

  4. 循环等待:若干进程直接形成一种头尾相接的循环等待关系

解决死锁:
​ 只要打破死锁必要条件中的一个就可以解决死锁问题

###减小锁的持有时间

1
2
3
4
5
public synchronized void someMethod(){
method1();
method2();
method3();
}

如果只有method2是需要同步的,而method1和method3不需要同步的话,直接在method2执行时进行同步,这样可明显减少锁的持有时间,提高系统的吞吐量。

1
2
3
4
5
6
7
public void someMethod() {
method1();
synchronized (this) {
method2();
}
method3();
}

###减少锁粒度
JDK并发中的ConcurrentHashMap很好的使用拆分锁对象的方式提高ConcurrentHashMap的吞吐量,ConcurrentHashMap将整个HashMap分成若干个段(Segment),
每一个段都是一个子HashMap,如果需要在ConcurrentHashMap中增加一个新的表列,并不是整个ConcurrentHashMap加锁,而是根据hashcode得到该表的项应该放
到哪个段中,然后对这个段加锁,并完成put()操作,只要加入的表项不存在同一个段中,则线程之间可以实现真正的并行。

然而减少锁粒度会引入一个新的问题,如果要获取全局锁的时候,消耗的资源会比较多。如ConcurrentHashMap中put()方法很好的分离了锁,但是在获取全局信息
如获取size()的时候,它将返回所有段的数量之和,而获取的时候需要获取所有段的锁,事实上,size()方法先使用无锁的方式求和,如果失败后才会尝试使用加锁
的方式获取。但在高并发的场景中,size()方法的性能仍然差于SynchronizedHashMap,因此,只有在类似于size()获取全局信息调用不频繁的时候,这种减小锁
粒度的方法才能真正的提高系统吞吐量。

文章目录
|