ToB企服应用市场:ToB评测及商务社交产业平台

标题: Java锁 从乐观锁和灰心锁开始讲 面试复盘 [打印本页]

作者: 曂沅仴駦    时间: 2025-1-20 03:08
标题: Java锁 从乐观锁和灰心锁开始讲 面试复盘
目录

面试复盘
Java 中的锁 大全
灰心锁
专业表明
自我理解
乐观锁
专业表明
自我理解
灰心锁的调用
乐观锁的调用
synchronized和 ReentrantLock的区别
雷同点
区别
具体对比
总结


面试复盘



Java 中的锁 大全



灰心锁

专业表明

得当写操纵多的场景
先加锁可以保证写操纵时数据精确
显式的锁定之后再操纵同步资源
自我理解

灰心锁以为自己使用数据的时间一定有其他线程来修改数据
因此在获取数据的时间会选择先加锁
确保数据不会被别的线程修改
synchronized 和 Lock 的实现类都是灰心锁

乐观锁

专业表明

得当读操纵多的场景
不加锁的特点能够使其读操纵的性能大幅提拔
乐观锁则能直接去操纵同步资源
是一种无锁算法
自我理解

乐观锁以为自己在操纵数据的时间不会有别的线程修改数据,所以不会加锁,所以他只会在自己操纵数据的时间检查是否有其他线程修改更新的这个数据。
如果乐观锁去操纵数据,这个数据没有更新的话。当火线程会直接将修改乐成的数据写入,如果数据已经被其他线程更新了。要通过不同的实现方式举行不同操纵。乐观锁在Java中是通过使用无锁编程来实现的,常用的是CAS算法。
Java原子类中的递增操纵就是用CAS 自旋完成的

灰心锁的调用



  1. import java.util.concurrent.locks.ReentrantLock;
  2. public class OptiPessLockDemo {
  3.     // 悲观锁的调用方式
  4.     public  synchronized void m1(){
  5.         // 加锁后的业务逻辑...
  6.     }
  7.     // 保证多个线程使用的是同一个lock对象的前提下
  8.     ReentrantLock lock=new ReentrantLock();
  9.     public void m2(){
  10.         lock.lock();
  11.         try {
  12.             // 操作同步资源
  13.         }finally {
  14.             lock.unlock();
  15.         }
  16.     }
  17.     // 两个都是悲观锁
  18. }
复制代码
假设在任何时间都可能发生冲突,因此,线程必须显式地获取锁以确保数据一致性和线程安全,直到它实行完毕并释放锁。
对于 synchronized,在方法级别加锁时,锁是针对该对象的,保证同一时刻只有一个线程能够实行该方法。因此,当一个线程在实行 m1() 方法时,其他线程不能同时实行同一个对象上的 m1() 方法。

乐观锁的调用



  1. import java.util.concurrent.atomic.AtomicInteger;
  2. import java.util.concurrent.locks.ReentrantLock;
  3. public class OptiPessLockDemo2 {
  4.     // 乐观锁的调用方式
  5.     private AtomicInteger atomicInteger = new AtomicInteger();
  6.     atomicInteger.incrementAndGet();
  7.     public static void main(String[] args) {
  8.         int oldValue = atomicInteger.get();
  9.         int newValue = oldValue + 1;
  10.         // 如果值没有被修改,原子性操作成功
  11.         return atomicInteger.compareAndSet(oldValue, newValue);
  12.     }
  13. }
复制代码
这种方式在判定和更新之间,确保了只有一个线程能够乐成更新值,其他线程则会重试或失败,从而保证了乐观锁的行为。
总之,乐观锁的核心是盼望在操纵时不加锁,直到最后验证冲突发生与否。如果有冲突,则可以通过重试、回滚等方式处置处罚。

synchronized和 ReentrantLock的区别

synchronized 和 ReentrantLock 都用于实现 灰心锁(Pessimistic Locking),即在多线程环境中对共享资源举行加锁,以保证线程安全。尽管两者实现的目标雷同,它们在使用方式、机动性、性能等方面有一些不同。下面我们来具体分析它们的 雷同点区别
雷同点






区别

特性
synchronized
ReentrantLock
实现方式
隐式加锁,Java 编译器在编译时自动处置处罚。
显式加锁,必要手动调用 lock()
和 unlock()

锁粒度
锁定整个方法或代码块,无法精确控制。
可以精确控制锁定的范围,答应更机动的锁定操纵。
性能
相对较低,特别是在高并发环境下,由于 JVM 的锁优化不足,可能导致性能瓶颈。
在高并发时,ReentrantLock
性能优于 synchronized
,尤其在锁竞争激烈时。
中断支持
不支持中断,线程获取锁时无法响应中断。
支持中断,可以使用 lockInterruptibly()
来在等候锁时响应中断。
公平性
非公平锁,线程不一定按照哀求的顺序获取锁。
可以选择公平锁或非公平锁。使用构造函数 new ReentrantLock(true)
来创建公平锁。
死锁制止
必要小心死锁问题,synchronized
无法制止死锁。
通过 ReentrantLock
提供的 tryLock()
方法和超时机制可以更机动地制止死锁。
锁释放机制
锁由 JVM 自动管理,方法实行完后自动释放。
必须手动调用 unlock()
释放锁,通常与 try...finally
语句配合使用。
可重入性
支持,可同一线程多次获取同一锁。
支持,可同一线程多次获取同一锁。
性能监控
无法直接获取锁的状态。
可以通过 getHoldCount()
获取当火线程持有锁的次数,举行监控。
锁升级
不支持锁的升级(无法从轻量级锁升级为重量级锁)。
可以通过锁的竞争情况动态升级为不同的锁类型(如偏向锁、轻量锁、重量锁)。

具体对比








总结


如果你的应用需求比力简单,且对性能要求不高,使用 synchronized 就足够了。如果你必要更多的控制、机动性和对高并发场景的优化,ReentrantLock 会是更好的选择。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4