面试题答案
一键面试线程安全问题
- 内存竞争:多个线程同时请求分配堆内存时,可能会发生竞争,导致数据不一致。例如,线程A和线程B同时尝试向同一内存地址写入对象引用,可能会覆盖对方的数据。
- 对象初始化不一致:如果对象的初始化过程涉及多个步骤,多个线程并发分配对象时,可能出现部分初始化的对象被其他线程使用的情况,导致程序出现难以调试的错误。
JVM保障机制及原理
- CAS(Compare - And - Swap)
- 原理:CAS是一种乐观锁机制。它包含三个操作数:内存位置(V)、预期原值(A)和新值(B)。当且仅当V的值等于A时,才会将V的值设为B。在堆内存分配中,使用CAS操作可以确保只有一个线程能成功分配到内存。例如,多个线程尝试分配内存块时,通过CAS操作比较内存块的状态(如是否已分配),只有比较成功的线程才能进行分配。
- TLAB(Thread - Local Allocation Buffer)
- 原理:为每个线程预先分配一块私有内存区域,称为TLAB。线程在分配对象时,首先尝试在自己的TLAB中分配。只有当TLAB用尽时,才会从共享堆内存中分配。这样可以减少线程之间对堆内存分配的竞争,因为大部分对象分配操作在各自的TLAB内完成,只有在TLAB不足时才会涉及到共享堆内存的竞争,从而提高了并发性能。
- 偏向锁、轻量级锁和重量级锁
- 偏向锁:原理是假设在大多数情况下,锁总是由同一线程多次获得,不存在多线程竞争。当一个线程访问同步块并获取锁时,会在对象头中记录该线程的ID,以后该线程再次进入和退出同步块时,不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word中是否存储着指向当前线程的偏向锁。如果测试成功,表示线程已经获得了锁。
- 轻量级锁:当偏向锁失效(即有第二个线程访问同步块)时,会升级为轻量级锁。它的原理是在没有竞争的情况下,使用CAS操作在对象头的Mark Word中设置指向线程栈中锁记录的指针。如果成功,就表示该线程获取了锁;如果失败,表示存在竞争,锁就会膨胀为重量级锁。
- 重量级锁:重量级锁是基于操作系统的互斥锁实现的。当轻量级锁竞争加剧,就会升级为重量级锁。线程获取重量级锁时,会进入阻塞状态,等待锁的释放。这种锁机制会导致线程上下文切换,开销较大,但能保证在高竞争情况下的线程安全。