1.减少锁持有时间
2.锁粗化
3.减少锁的粒度(经典应用场景:JDK1.8 ConcurrentHashMap的 put()方法)
对于ConcurrentHashMap其最重要的2个API就是 get()和put()。高并发场景下为了保证容器线程安全,最自然的做法就是对整个ConcurrentHashMap加锁,其实可以优化。来看ConcurrentHashMap的底层实现:数组+单向链表的数据结构,JDK1.8后优化为红黑树,红黑树其实就是一棵自平衡的二叉树,如果单向链表的长度>8时 它会自动左旋右旋。整个ConcurrentHashMap分为16段,可以类比为16个水桶编号0~15,put 数据时,先对数据进行一次hash算法,得出hashcode,根据这个hashcode决定数据要放在的水桶编号,例如数据24进行一次hash得出的hashcode=8,此时会拿到8号水桶会拿到一个分段锁Segment,分段锁相当于水桶盖子封住8号水桶,直至这个数据24会插入到单向链表的末尾put完成,假如桶封住的时候,有其它多个线程要把数据放到8号桶,只能先排队,待24放好以后会释放掉锁,然后其它线程才可以put。但是在同一时刻,其它桶的put操作互不影响,可以同时进行,这就大大的提高了ConcurrentHashMap的性能。
Segment源码实现:
put()方法源码实现:
4.锁分离(举例:LinkBlockingQueue的take()方法和put()方法)
通过takeLock 和 putLock 两把锁 ,实现LinkedBlcokingQueue 取数据和写数据的分离。
1.take()的源码实现
2.put()的源码实现
5.用读写分离锁ReadWriteLock来替换独占锁Synchronized(这种锁优化是减小锁粒度的一种特殊情况)
如果说减小锁粒度是通过分割数据结构实现的,那么ReadWriteLock则是通过对系统功能点的分割。
ReadWriteLock 其实是定义为接口,ReentrantReadWriteLock是它的一个具体实现