java进阶(5)之ReentranctLock/AQS等并发原理解析
PS: AQS全称AbstractQueueSynchronizer,抽象队列同步器,是并发中最核心的一个类了,本篇文章不剖析源码,只用文字和图形表达。
AQS解析以及与ReentranctLock之间的关系
通过看源码可知,ReentranctLock
关于锁的操作,都是基于AQS的。
AQS中有两个核心的属性,状态变量state
和双向链表head
和tail
。state
用于保存当前是否有锁以及锁的种类(读or写),默认值为0,通过VarHandle.compareAndSet(this, expect, update)
,来改变字段值(这个就是传说中的CAS操作,基于底层操作系统,能保证原子性)。JDK开发人员也巧妙地将int类型的state
的高低16位,分别代表锁的读和写,从而能让一个参数,存储到读和写两个状态.
双向链表head
和tail
,用于将阻塞的线程加入到队尾中,然后从队首取出阻塞的线程进行消费。
ReentrantReadWriteLock解析
其实跟ReentrantLock
类似,只是ReentrantReadWriteLock
有ReadLock
和WriteLock
两把锁。说是两把锁,但是两个对象,都是使用的AQS
中的锁,也就是通过state
变量控制读写锁状态,并且通过AQS里内部算法实现:读写锁互斥,写写锁互斥,读读锁正常取值。
锁优化的策略
- 标志位修改等可减刑场景优先使用volatile
- 数值递增场景优先使用Atomic原子类
- 数据允许多副本场景优先使用ThreadLocal
- 读多写少需要加锁的场景优先使用读写锁
- 尽可能减少线程对锁占用的时间
- 尽可能减少线程对数据加锁的粒度
- 尽可能对不同功能分离锁的使用
- 避免在循环中频繁的加锁以及释放锁
- 尽量减少高并发场景中线程对锁的争用
- 采用多级缓存机制降低线程对锁对争用
- 生产环境如遇死锁情况可用jstack进行分析