Synchronized & Lock
- Synchronized 可以用于类,方法,代码块加锁;Lock只能作用于代码块
- Synchronized 不需要手动获取锁,释放锁,更简单;Lock如果没有unlock()可能会带来一些问题
- Lock 可以通过lock()判断是否获取到了锁,而Synchronized不能
Synchronized & ReentrantLock
- 二者皆为可重入锁
- Synchronized 基于JVM实现(monitorenter指令);ReentrantLock基于API实现(可以理解为,一个在机器码层,一个在应用层)
- ReentrantLock功能更加全面,支持公平非公平模式,支持中断并放弃获取锁,支持Condition来实现线程之间的调度,更加灵活
使用选择
- 除非需要使用到ReentrantLock的高级功能,尽量使用Synchronized,更简单,JVM原生支持
Synchronized 锁的升级
升级顺序为 无锁 》 偏向锁 》 轻量锁 》 重量锁
Synchronized 使用的锁存放在Java对象头的MarkWord里,其中存储了同步状态、标识、hashcode、GC状态等信息
- 偏向锁
多数情况下,锁的使用并不存在多线程竞争,并且总是由同一个线程获得;因此引入偏向锁,降低线程首次获得锁的代价;偏向锁会偏向于第一个访问锁的线程,在程序运行中,只有一个线程访问同步锁,不存在多线程争用的情况,则线程不需要触发同步,直接给该线程加一个偏向锁 - 轻量锁
当发生锁的竞争时,偏向锁会升级为轻量级锁,轻量锁是自旋锁;轻量锁的设计思想是,如果持有锁的线程能够在很短时间内释放锁,则等待的线程可以不作上下文切换,只是进行数次自旋等待,持有锁的线程释放锁后即可立即获取锁,从而避免上下文切换的开销(上下文切换比执行CPU指令的开销要大的多) - 重量锁
线程自旋是需要占用CPU的,因此需要设定一个自旋等待的最大时间,当持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁,则竞争锁的线程会停止自旋进入阻塞状态,此时升级到重量级锁,JDK1.6中引入了适应性自旋锁,自旋的时间不再固定,而是由上一次在同一个锁上的自旋时间以及锁的拥有者的状态来决定,基本认为是一个线程上下文切换的时间
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。