Java并发编程面试题: 并发理论( 乐观锁 & 悲观锁、CAS、死锁 & 活锁 & 饥饿 )

收集大量Java经典面试题目📚,内容涵盖了包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 等知识点🏝️。适合准备Java面试的读者参考和复习🌟📢。

❗ ❗ ❗ 关注公众号:枫蜜柚子茶 ✅✅🗳
📑 回 复 “ Java面试 ” 获 取 完 整 资 料⬇ ⬇ ⬇

📖Java并发编程面试Top123道题🔥🔥
1️⃣ 基 础 知 识 
2️⃣ 并 发 理 论 🚩
3️⃣ 线 程 池  
4️⃣ 并 发 容 器

5️⃣ 并 发 队 列

6️⃣ 并 发 工 具 类

1. 乐观锁和悲观锁的理解及如何实现,有哪些实现方式?

        悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候 都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多 这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。再比如 Java 里面的   同步原语 synchronized 关键字的实现也是悲观锁。

        乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是 在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适 用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于 write_condition 机制,其实都是提供的乐观锁。在 Java中 java.util.concurrent.atomic 包下面的原子变量类就是使用了乐观锁的一种实现方式 CAS 实现的。

2. 什么是 CAS

 CAS compare and swap 的缩写,即我们所说的比较交换。

        cas 是一种基于锁的操作,而且是乐观锁。 java 中锁分为乐观锁和悲观锁。悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。而乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加 version 来获取数据,性能较悲观锁有很大的提高。

        CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存地址里面的值和 A 的值是一样的,那么就将内存里面的值更新成 BCAS是通过无限循环来获取数据的,若果在第一轮循环中, a 线程获取地址里面的值被b 线程修改了,那么 a 线程需要自旋,到下次循环才有可能机会执行。

  •   java.util.concurrent.atomic 包下的类大多是使用 CAS 操作来实现的  
  •   (AtomicInteger,AtomicBoolean,AtomicLong)  

3. CAS 的会产生什么问题?

1️⃣. ABA 问题:

        比如说一个线程 one 从内存位置 V 中取出 A,这时候另一个线程 two 也从内存中取出 A,并且 two 行了一些操作变成了 B,然后 two 又将 V 位置的数据变成 A,这时候线程 one 进行 CAS 操作发现内存中仍然是 A,然后 one 操作成功。尽管线程 one CAS 操作成功,但可能存在潜藏的问题。从Java1.5 开始 JDK atomic包里提供了一个类 AtomicStampedReference 来解决 ABA 问题。 

2️⃣. 循环时间长开销大:

对于资源竞争严重(线程冲突严重)的情况, CAS 自旋的概率会比较大,从而浪费更多的 CPU 资源, 效率低于 synchronized

3️⃣. 只能保证一个共享变量的原子操作:

当对一个共享变量执行操作时,我们可以使用循环 CAS 方式来保证原子操作,但是对多个共享变量 操作时,循环 CAS 就无法保证操作的原子性,这个时候就可以用锁。

4. 什么是原子类

        java.util.concurrent.atomic包:是原子类的小工具包,支持在单个变量上解除锁的线程安全编程原子变量类相当于一种泛化的 volatile 变量,能够支持原子的和有条件的读--写操作。

        比如:AtomicInteger 表示一个int类型的值,并提供了 get set 方法,这些 Volatile 类型的int 变量在读取和写入上有着相同的内存语义。它还提供了一个原子的 compareAndSet 方法(如果该 方法成功执行,那么将实现与读取/写入一volatile 变量相同的内存效果),以及原子的添加、递增和递减等方法。 AtomicInteger 表面上非常像一个扩展的 Counter 类,但在发生竞争的情况 下能提供更高的可伸缩性,因为它直接利用了硬件对并发的支持。

   ❗  简单来说就是原子类来实现CAS无锁模式的算法    

5. 原子类的常用类

  •         ◾  AtomicBoolean 
    •         ◾  AtomicInteger
      •         ◾  AtomicLong
        •         ◾  AtomicReference

6. 说一下 Atomic的原理

        Atomic包中的类基本的特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引用类型)变量进行操作时,具有排他性,即当多个线程同时对该变量的值进行更新时,仅有一个线 程能成功,而未成功的线程可以向自旋锁一样,继续尝试,直等到执行成功。

 

7. 死锁与活锁的区别,死锁与饥饿的区别?

        死锁:是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

        ​​​​​​​活锁:任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试,失败,尝试,失败。

💡活锁和死锁的区别在于,处于活锁的实体是在不断的改变状态,这就是所谓的 , 而处于死锁的 实体表现为等待;活锁有可能自行解开,死锁则不能。

饥饿:一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行的状态。 

Java 中导致饥饿的原因:

  • 1️⃣ . 高优先级线程吞噬所有的低优先级线程的 CPU 时间。
  • 2️⃣. 线程被永久堵塞在一个等待进入同步块的状态,因为其他线程总是能在它之前持续地对该 同步块进行访问。
    • 3️⃣. 线程在等待一个本身也处于永久等待完成的对象(比如调用这个对象的 wait 方法),因为其 他线程总是被持续地获得唤醒。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫蜜柚子茶

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值