参见更好的整理
Java中的锁
代码及虚拟机配置级别锁优化
减少锁持有的时间
- 同步方法细化为同步代码块
减小锁粒度
ConcurrentHashMap实现
好处
- 将大对象拆分为小对象,增大并行度,降低锁竞争。
- 偏向锁、轻量级锁成功率高。
锁分离
- ReadWriteLock
- 读写分离,读锁之间不会相互阻塞。
- 联想forkjoin线程池的工作偷取机制
- LinkedBlockingQueue实现
Java并发集合实现原理
锁粗化
- 锁的获取释放,也是需要付出一些性能代价的。
- 针对与那些需要频繁获取锁,释放锁的操作,而且每个操作的持有锁的时间很短。
锁消除
- 基于编译器级别的
- 对于一些线程安全的对象,比如StringBuilder,如果该对象是线程封闭的,即非逸出对象,那么该对象就是运行在单线程中的,这样它的同步机制会带来性能负担,通过JVM的配置,让编译器自动优化这种代码。
虚拟机内的锁优化
偏向锁
对象头
- 32位
- 描述对象Hash
- 锁信息
- 垃圾回收标志
- 年龄
- 偏向锁线程ID
- 已经分配了该锁的线程
- 在没有竞争的条件下,获得偏向锁的线程ID,在进入同步代码块的时候不需要进行同步操作。
- 适用于竞争少的场景。
- 命令
-XX:+UseBiasedLocking
默认是启用的
轻量级锁
- 快速判断线程是否持该对象的锁。
- 在线程栈中开辟一块空间作为 锁记录
BasicObjectLock
。 - 通过CAS操作,尝试将修改共享对象的头信息中的Mark指针,指向栈空间开辟的 锁记录。
- 如果失败了,进行自旋。
- 如果自旋失败了,则守护共享对象的锁膨胀为重量级的锁。
- 同样适用于竞争少的情况下。
自旋锁
int i=100 -> while(i--){//空操作}
- 避免线程挂起。
ThreadLocal源码实现
ThreadLocalMap核心对象
- key是ThreadLocal实例 value是需要封闭在当前线程中的变量
- ThreadLocalMap 线程的成员变量
- 内部Entry[] 数组
- Entry是继承自弱引用的
WeakReference<ThreadLocal>
cleanSomeSlots()
清理无用对象。