分析&回答
公平锁和非公平锁
- 公平锁:是指按照申请锁的顺序来获取锁。
- 非公锁:线程获取锁的顺序不一定按照申请锁的顺序来的。
- ReentrantLock 默认是不公平锁,传入true为公平锁,否则为非公平锁
共享锁和独享锁
- 独享锁:一次只能被一个线程所访问
- 共享锁:线程可以被多个线程所持有。
- ReadWriteLock 读锁是共享锁,写锁是独享锁。
乐观锁和悲观锁。
- 乐观锁:对于一个数据的操作并发,是不会发生修改的。在更新数据的时候,会尝试采用更新,不断重入的方式,更新数据。
- 乐观锁适合于读取频繁;
- 乐观锁是先进行业务逻辑再加锁;
- 悲观锁:对于同一个数据的并发操作,是一定会发生修改的。因此对于同一个数据的并发操作,悲观锁采用加锁的形式。悲观锁认为,不加锁的操作一定会出问题。
- 悲观锁适合于写频繁;
- 悲观锁是先加锁后进行业务逻辑;
分段锁
1.7及之前的ConcurrentHashMap。并发操作就是分段锁,其思想就是让锁的粒度变小。
偏向锁
对象的代码一直被同一线程执行,不存在多个线程竞争,该线程在后续的执行中自动获取锁,降低获取锁带来的性能开销。偏向锁,指的就是偏向第一个加锁线程,该线程是不会主动释放偏向锁的,只有当其他线程尝试竞争偏向锁才会被释放。
偏向锁的撤销,需要在某个时间点上没有字节码正在执行时,先暂停拥有偏向锁的线程,然后判断锁对象是否处于被锁定状态。
- 如果线程不处于活动状态,则将对象头设置成无锁状态,并撤销偏向锁;
- 如果线程处于活动状态,升级为轻量级锁的状态。
轻量级锁
轻量级锁是指当锁是偏向锁的时候,被第二个线程 B 所访问,此时偏向锁就会升级为轻量级锁,线程 B 会通过自旋的形式尝试获取锁,线程不会阻塞,从而提高性能。
当前只有一个等待线程,则该线程将通过自旋进行等待。但是当自旋超过一定的次数时,轻量级锁便会升级为重量级锁;当一个线程已持有锁,另一个线程在自旋,而此时又有第三个线程来访时,轻量级锁也会升级为重量级锁。
重量级锁
指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。
重量级锁通过对象内部的监视器(monitor)实现,而其中 monitor 的本质是依赖于底层操作系统的 Mutex Lock 实现,操作系统实现线程之间的切换需要从用户态切换到内核态,切换成本非常高。
自旋锁
当一个线程尝试去获取某一把锁的时候,如果这个锁此时已经被别人获取(占用),那么此线程就无法获取到这把锁,该线程将会等待,间隔一段时间后会再次尝试获取。这种采用循环加锁 -> 等待的机制被称为自旋锁(spinlock)。
反思&扩展
- 锁技术是慢的!
- 没有竞争=没有锁=非常快!
- 合理利用锁非常重要!
读写锁可以用于什么应用场景?
喵呜面试助手: 一站式解决面试问题,你可以搜索微信小程序 [喵呜面试助手] 或关注 [喵呜刷题] -> 面试助手 免费刷题。如有好的面试知识或技巧期待您的共享!