1. 作用
确保线程互斥访问同步代码块、保证共享变量的修改能及时可见、有效解决重排序问题。
2. 作用范围
修饰普通方法,修饰静态方法,修饰代码块
3. 原理:
每个对象都有一个监视器锁(mointor)。当monitor被占用时就会处于锁定状态。
1. 线程首次执行monitorenter指令时会尝试获取monitor的所有权:
A.首次进入,monitor进入数设置为1,线程持有monitor
B.重新进入,monitor进入数+1
2.其他线程进入时,mointor已经占用,则进入阻塞状态,知道monitor进入数为0,则尝试获取锁。
A.线程执行monitorexit时,monitor进入数-1,然后如果进入数为0,则线程退出monitor。
4. JVM锁优化
锁粗化:消除没必要的紧连一起的unlock和lock操作,将多个连续的锁扩展成一个范围更大的锁
锁消除:通过JIT编译器的逃逸分析消除一些没有在当前同步块以外被其他线程共享的数据的锁保护
轻量级锁:这种锁实现的背后基于这样一种假设,即在真实的情况下我们程序中的大部分同步代码一般都处于无锁竞争状态(即单线程执行环境),在无锁竞争的情况下完全可以避免调用操作系统层面的重量级互斥锁,取而代之的是在monitorenter和monitorexit中只需要依靠一条CAS原子指令就可以完成锁的获取及释放。当存在锁竞争的情况下,执行CAS指令失败的线程将调用操作系统互斥锁进入到阻塞状态,当锁被释放的时候被唤醒(具体处理步骤下面详细讨论)
偏向锁:是为了在无锁竞争的情况下避免在锁获取过程中执行不必要的CAS原子指令,因为CAS原子指令虽然相对于重量级锁来说开销比较小但还是存在非常可观的本地延迟
适应性自旋:当线程在获取轻量级锁的过程中执行CAS操作失败时,在进入与monitor相关联的操作系统重量级锁前会进入忙等待然后在尝试,尝试一定次数后任没有成功,则调用与该monitor关联的semaphore(即互斥锁)进入到阻塞状态。
4. 和Lock的对比
1. synchronized是JVM级别的锁,而Lock是java代码实现的锁
2. synchronized不需要主动释放锁,而Lock需要主动释放
3. synchronized会一直阻塞,而Lock有多种模式可以选择
4. 两者效率都差不多
网友评论