面试 Java 并发编程八股文十问十答第六期

2024-03-13 13:12

本文主要是介绍面试 Java 并发编程八股文十问十答第六期,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

面试 Java 并发编程八股文十问十答第六期

作者:程序员小白条,个人博客

相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!

⭐点赞⭐收藏⭐不迷路!⭐

1)synchronized 和 ReentrantLock 区别是什么?

  • 锁的获取方式:synchronized 是隐式锁,通过在方法或代码块上加上 synchronized 关键字来获取锁,而 ReentrantLock 是显式锁,需要通过调用 lock() 方法来获取锁。
  • 锁的释放方式:synchronized 在代码块执行完毕或方法返回时会自动释放锁,而 ReentrantLock 需要在 finally 块中显式调用 unlock() 方法来释放锁,确保锁的释放。
  • 可重入性:ReentrantLock 是可重入锁,同一个线程可以多次获取同一把锁,而 synchronized 也是可重入的,但是要求是同一个线程在持有锁的情况下才能再次获取锁。
  • 等待可中断:ReentrantLock 提供了可中断的获取锁的方式,通过调用 lockInterruptibly() 方法可以使等待锁的线程响应中断,而 synchronized 则不支持中断。
  • 公平性:ReentrantLock 可以通过构造函数指定是否是公平锁,即按照线程的请求顺序来获取锁,默认是非公平锁,而 synchronized 是非公平锁。
  • 扩展性:ReentrantLock 提供了更多的功能,比如可定时的、可轮询的、可中断的获取锁的方式,以及公平锁的支持等,而 synchronized 的功能相对较少。

2)volatile 关键字的作用

volatile 关键字的作用是保证变量的可见性和禁止指令重排序。具体来说,volatile 修饰的变量在多线程环境下的写操作会立即刷新到主内存,并且在读操作时会从主内存中获取最新的值,而不是使用线程私有的缓存。这样可以保证不同线程之间对该变量的操作是正确可见的。

此外,volatile 修饰的变量也禁止了指令重排序优化,保证了特定操作的执行顺序。这对于一些需要保证顺序性的场景非常重要,例如双重检查锁定(Double-Checked Locking)中的单例模式。

需要注意的是,volatile 并不能保证原子性,即不能保证多个线程同时执行的复合操作的原子性,如果需要保证原子性,需要使用其他的同步机制,比如使用 synchronized 或者使用原子类。

3)Java 中能创建 volatile 数组吗?

在 Java 中,不能直接创建 volatile 数组。volatile 关键字只能修饰类的成员变量或者类的静态变量,不能直接修饰数组。如果需要将整个数组作为一个原子性操作进行处理,可以使用 AtomicIntegerArray 或者 AtomicReferenceArray 等原子类来代替。这些原子类提供了对数组元素的原子性操作,可以满足多线程环境下对数组的需求。

4)volatle 变量和 atomic 变量有什么不同?

  • 可见性:volatile 变量保证了可见性,即对一个 volatile 变量的写操作对于其他线程是可见的,而 atomic 变量也保证了可见性。
  • 原子性:atomic 变量提供了一些原子性操作,例如 atomicInteger 的自增和自减操作是原子的,而 volatile 变量本身并不保证原子性。
  • 内存屏障:atomic 变量通过使用底层的 CAS(Compare and Swap)操作来保证原子性,这会涉及到底层的内存屏障操作,而 volatile 变量也会使用内存屏障来保证可见性。
  • 顺序性:atomic 变量提供了一些有序性保证的方法,例如使用 AtomicInteger 的 getAndSet() 方法可以保证写操作的顺序性,而 volatile 变量本身并不提供有序性保证。

5)volatile 能使得一个非原子操作变成原子操作吗?

volatile 不能使得一个非原子操作变成原子操作。volatile 只能保证可见性和禁止指令重排序,它并不能保证多个操作的原子性。如果需要保证多个操作的原子性,需要使用其他的同步机制,例如使用 synchronized 或者使用原子类。

6)volatile 修饰符的有过什么实践?

  • 保证变量的可见性:使用 volatile 修饰共享变量,可以确保对该变量的写操作对其他线程是可见的,从而实现线程间的通信。
  • 双重检查锁定(Double-Checked Locking):在单例模式中,使用 volatile 修饰单例对象的引用,可以确保在多线程环境下创建单例对象的安全性。
  • 控制循环条件:在某些情况下,使用 volatile 修饰循环条件可以实现线程之间的同步和协作,例如在一个线程中改变循环条件的值,从而使其他线程退出循环。
  • 实现轻量级的同步:相比于 synchronized,volatile 修饰符的开销更小,适用于一些对性能要求较高的场景,例如在一些读多写少的情况下,可以使用 volatile 修饰共享变量来实现轻量级的同步。

7)synchronized 和 volatile 的区别是什么?

  • 功能:synchronized 用于实现线程的互斥同步,保证同一时刻只有一个线程可以执行被 synchronized 修饰的代码块或方法;而 volatile 用于保证变量的可见性和禁止指令重排序。
  • 用法:synchronized 通过在代码块或方法上加上 synchronized 关键字来获取锁,而 volatile 通过修饰变量来实现可见性和禁止指令重排序。
  • 原子性:synchronized 可以保证代码块或方法的原子性,即同一时刻只有一个线程可以执行,而 volatile 本身并不保证原子性。
  • 内存屏障:synchronized 使用内存屏障来保证可见性和有序性,而 volatile 也使用内存屏障来保证可见性和禁止指令重排序。
  • 适用范围:synchronized 适用于复杂的线程同步场景,可以保证线程安全;而 volatile 适用于简单的变量共享场景,可以保证变量的可见性。

8)什么是不可变对象,它对写并发应用有什么帮助?

不可变对象是指创建后不可被修改的对象。它对写并发应用有很大的帮助,因为不可变对象不会发生状态的改变,所以多个线程可以同时访问不可变对象而不需要额外的同步控制。这样可以避免了线程之间的竞争和冲突,提高了并发性能和线程安全性。

不可变对象的特点是:对象创建后状态不可变、属性都是 final 和 private、没有提供修改状态的方法。常见的不可变对象有 String、Integer、BigDecimal 等。

9)Java Concurrency API 中的 Lock 接口(Lock interface)是什么?对比同步它有什么优势?

  • 可中断性:Lock 接口提供了可以响应中断的获取锁的方式,通过 lockInterruptibly() 方法可以使等待锁的线程响应中断。
  • 公平性:Lock 接口可以实现公平锁,即按照线程的请求顺序来获取锁。
  • 条件变量:Lock 接口提供了 Condition 接口,可以通过 Condition 实现线程的等待和唤醒操作,实现更灵活的线程同步。
  • 可重入性:Lock 接口和 synchronized 关键字一样,都支持可重入性,同一个线程可以多次获取同一把锁。
  • 灵活性:Lock 接口提供了更多的功能,例如可定时的、可轮询的、可中断的获取锁的方式,以及公平锁的支持等。

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

  • 乐观锁:乐观锁的思想是假设在并发情况下不会发生冲突,所以不加锁直接进行操作,当发生冲突时再进行处理。乐观锁的实现方式包括版本号机制、CAS(Compare and Swap)操作等。
  • 悲观锁:悲观锁的思想是假设在并发情况下会发生冲突,所以在操作前先加锁,确保同一时刻只有一个线程可以访问共享资源。悲观锁的实现方式包括 synchronized 关键字、Lock 接口等。

乐观锁和悲观锁的选择取决于具体的应用场景和需求。乐观锁适用于读多写少的情况,可以提高并发性能;而悲观锁适用于写多读少的情况,可以保证数据的一致性和安全性。在实际应用中,可以根据具体的业务需求选择合适的锁机制。

开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system

前后端总计已经 800+ Star,1.5W+ 访问!

⭐点赞⭐收藏⭐不迷路!⭐

这篇关于面试 Java 并发编程八股文十问十答第六期的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/805002

相关文章

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

Spring Boot中JSON数值溢出问题从报错到优雅解决办法

《SpringBoot中JSON数值溢出问题从报错到优雅解决办法》:本文主要介绍SpringBoot中JSON数值溢出问题从报错到优雅的解决办法,通过修改字段类型为Long、添加全局异常处理和... 目录一、问题背景:为什么我的接口突然报错了?二、为什么会发生这个错误?1. Java 数据类型的“容量”限制

Java对象转换的实现方式汇总

《Java对象转换的实现方式汇总》:本文主要介绍Java对象转换的多种实现方式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java对象转换的多种实现方式1. 手动映射(Manual Mapping)2. Builder模式3. 工具类辅助映

SpringBoot请求参数接收控制指南分享

《SpringBoot请求参数接收控制指南分享》:本文主要介绍SpringBoot请求参数接收控制指南,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring Boot 请求参数接收控制指南1. 概述2. 有注解时参数接收方式对比3. 无注解时接收参数默认位置

SpringBoot基于配置实现短信服务策略的动态切换

《SpringBoot基于配置实现短信服务策略的动态切换》这篇文章主要为大家详细介绍了SpringBoot在接入多个短信服务商(如阿里云、腾讯云、华为云)后,如何根据配置或环境切换使用不同的服务商,需... 目录目标功能示例配置(application.yml)配置类绑定短信发送策略接口示例:阿里云 & 腾

SpringBoot项目中报错The field screenShot exceeds its maximum permitted size of 1048576 bytes.的问题及解决

《SpringBoot项目中报错ThefieldscreenShotexceedsitsmaximumpermittedsizeof1048576bytes.的问题及解决》这篇文章... 目录项目场景问题描述原因分析解决方案总结项目场景javascript提示:项目相关背景:项目场景:基于Spring

Spring Boot 整合 SSE的高级实践(Server-Sent Events)

《SpringBoot整合SSE的高级实践(Server-SentEvents)》SSE(Server-SentEvents)是一种基于HTTP协议的单向通信机制,允许服务器向浏览器持续发送实... 目录1、简述2、Spring Boot 中的SSE实现2.1 添加依赖2.2 实现后端接口2.3 配置超时时

Spring Boot读取配置文件的五种方式小结

《SpringBoot读取配置文件的五种方式小结》SpringBoot提供了灵活多样的方式来读取配置文件,这篇文章为大家介绍了5种常见的读取方式,文中的示例代码简洁易懂,大家可以根据自己的需要进... 目录1. 配置文件位置与加载顺序2. 读取配置文件的方式汇总方式一:使用 @Value 注解读取配置方式二

一文详解Java异常处理你都了解哪些知识

《一文详解Java异常处理你都了解哪些知识》:本文主要介绍Java异常处理的相关资料,包括异常的分类、捕获和处理异常的语法、常见的异常类型以及自定义异常的实现,文中通过代码介绍的非常详细,需要的朋... 目录前言一、什么是异常二、异常的分类2.1 受检异常2.2 非受检异常三、异常处理的语法3.1 try-

Java中的@SneakyThrows注解用法详解

《Java中的@SneakyThrows注解用法详解》:本文主要介绍Java中的@SneakyThrows注解用法的相关资料,Lombok的@SneakyThrows注解简化了Java方法中的异常... 目录前言一、@SneakyThrows 简介1.1 什么是 Lombok?二、@SneakyThrows