【Java实习生面试题系列】-- 多线程篇三

x33g5p2x  于2022-04-29 转载在 Java  
字(2.2k)|赞(0)|评价(0)|浏览(518)
  • Day2,第三篇
  • 本篇文章的主题是 【Java实习生面试题系列】-- 多线程篇三

1. 说下对 ReentrantReadWriteLock 的理解?

首先 ReentrantLock 某些时候有局限,如果使用 ReentrantLock ,可能本身是为了防止线程A在写数据、线程B在读数据造成的数据不一致,但这样,如果线程C在读数据、线程D也在读数据,读数据是不会改变数据的,没有必要加锁,但是还是加锁了,降低了程序的性能。

因为这个,才诞生了读写锁 ReadWriteLockReadWriteLock 是一个读写锁接口,ReentrantReadWriteLockReadWriteLock 接口的一个具体实现,实现了读写的分离,读锁是共享的,写锁是独占的,读和读之间不会互斥,读和写、写和读、写和写之间才会互斥,提升了读写的性能

2. 说下对悲观锁和乐观锁的理解?

  • 乐观锁:乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。乐观锁适用于读多写少的场景,这样可以提高程序的吞吐量。
  • 悲观锁:之所以叫做悲观锁,是因为这是一种对数据的修改持有悲观态度的并发控制方式。总是假设最坏的情况,每次读取数据的时候都默认其他线程会更改数据,因此需要进行加锁操作,当其他线程想要访问数据时,都需要阻塞挂起。

3. 乐观锁常见的两种实现方式是什么?

  1. 版本号机制:就是会有一个 version 字段,就是每一次修改对应数据行的时候,我们都会对对应的版本号字段进行比较,如果和预期的相同就进行更新,否则更新失败。
  2. CAS算法:全称 Compare and swap,即比较并交换,它是一条 CPU 同步原语。是一种硬件对并发的支持,针对多处理器操作而设计的一种特殊指令,用于管理对共享数据的并发访问。
  • CAS 是一种无锁的非阻塞算法的实现。

  • CAS 包含了 3 个操作数:

  • 需要读写的内存值 V

  • 旧的预期值 A

  • 要修改的更新值 B

  • 当且仅当 V 的值等于 A 时,CAS 通过原子方式用新值 B 来更新 V 的 值,否则不会执行任何操作(他的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。)

CAS 并发原语体现在 Java 语言中的 sum.misc.Unsafe 类中的各个方法。调用 Unsafe 类中的 CAS 方法, JVM 会帮助我们实现出 CAS 汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。再次强调,由于 CAS是一种系统原语,原语属于操作系统用于范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的在执行过程中不允许被中断,CAS 是一条 CPU 的原子指令,不会造成数据不一致问题。

4. CAS有什么缺陷?

1. ABA 问题

并发环境下,假设初始条件是 A ,去修改数据时,发现是 A 就会执行修改。但是看到的虽然是 A ,中间可能发生了 ABB 又变回 A 的情况。此时 A 已经非彼 A ,数据即使成功修改,也可能有问题。

可以通过 **AtomicStampedReference**解决ABA问题,它,一个带有标记的原子引用类,通过控制变量值的版本来保证CAS的正确性

2. 循环时间长开销

自旋CAS,如果一直循环执行,一直不成功,会给CPU带来非常大的执行开销。

很多时候,CAS思想体现,是有个自旋次数的,就是为了避开这个耗时问题~

3. 只能保证一个变量的原子操作。

CAS 保证的是对一个变量执行操作的原子性,如果对多个变量操作时,CAS 目前无法直接保证操作的原子性的。

可以通过这两个方式解决这个问题

  • 使用互斥锁来保证原子性
  • 将多个变量封装成对象,通过 AtomicReference 来保证原子性。

5. CAS 和 synchronized 的使用场景?

  • 对于资源竞争较少的情况使用 synchronized
  • 对于资源竞争严重的情况,CAS 自旋的概率比较大。

6. 简单说下对 Java 中的原子类的理解?

Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。

所以,所谓原子类说简单点就是 具有原子 / 原子操作特征 的类。

并发包 java.util.concurrent 的原子类都存放在 java.util.concurrent.atomic 下:

7. AtomicInteger 的原理是什么?

AtomicInteger 类主要利用 CASvolatilenative 方法来保证原子操作,从而避免 synchronized 的高开销,执行效率大为提升。

AtomicInteger 类的部分源码:

// 更新操作时提供“比较并替换”的作用
  private static final Unsafe unsafe = Unsafe.getUnsafe();

  private static final long valueOffset;

  static {
      try{
          valueOffset = unsafe.objectFieldOffset(AutomicInteger.class.getDeclaredField("value"));
      }catch(Exception ex){
          throw new Error(ex);
      }
  }

  private volatile int value;

今天的面试题就总结这么一些吧,总结面试题也花费了我不少时间,所以说总结不易,如果你感觉对你有帮助的话,请你三连支持,后面的文章会一点点更新。

相关文章