面试 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

相关文章

Spring Cloud Hystrix原理与注意事项小结

《SpringCloudHystrix原理与注意事项小结》本文介绍了Hystrix的基本概念、工作原理以及其在实际开发中的应用方式,通过对Hystrix的深入学习,开发者可以在分布式系统中实现精细... 目录一、Spring Cloud Hystrix概述和设计目标(一)Spring Cloud Hystr

Spring Boot整合消息队列RabbitMQ的实现示例

《SpringBoot整合消息队列RabbitMQ的实现示例》本文主要介绍了SpringBoot整合消息队列RabbitMQ的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录RabbitMQ 简介与安装1. RabbitMQ 简介2. RabbitMQ 安装Spring

springMVC返回Http响应的实现

《springMVC返回Http响应的实现》本文主要介绍了在SpringBoot中使用@Controller、@ResponseBody和@RestController注解进行HTTP响应返回的方法,... 目录一、返回页面二、@Controller和@ResponseBody与RestController

JAVA集成本地部署的DeepSeek的图文教程

《JAVA集成本地部署的DeepSeek的图文教程》本文主要介绍了JAVA集成本地部署的DeepSeek的图文教程,包含配置环境变量及下载DeepSeek-R1模型并启动,具有一定的参考价值,感兴趣的... 目录一、下载部署DeepSeek1.下载ollama2.下载DeepSeek-R1模型并启动 二、J

springboot rocketmq配置生产者和消息者的步骤

《springbootrocketmq配置生产者和消息者的步骤》本文介绍了如何在SpringBoot中集成RocketMQ,包括添加依赖、配置application.yml、创建生产者和消费者,并展... 目录1. 添加依赖2. 配置application.yml3. 创建生产者4. 创建消费者5. 使用在

Spring Retry 实现乐观锁重试实践记录

《SpringRetry实现乐观锁重试实践记录》本文介绍了在秒杀商品SKU表中使用乐观锁和MybatisPlus配置乐观锁的方法,并分析了测试环境和生产环境的隔离级别对乐观锁的影响,通过简单验证,... 目录一、场景分析 二、简单验证 2.1、可重复读 2.2、读已提交 三、最佳实践 3.1、配置重试模板

Spring中@Lazy注解的使用技巧与实例解析

《Spring中@Lazy注解的使用技巧与实例解析》@Lazy注解在Spring框架中用于延迟Bean的初始化,优化应用启动性能,它不仅适用于@Bean和@Component,还可以用于注入点,通过将... 目录一、@Lazy注解的作用(一)延迟Bean的初始化(二)与@Autowired结合使用二、实例解

SpringBoot使用Jasypt对YML文件配置内容加密的方法(数据库密码加密)

《SpringBoot使用Jasypt对YML文件配置内容加密的方法(数据库密码加密)》本文介绍了如何在SpringBoot项目中使用Jasypt对application.yml文件中的敏感信息(如数... 目录SpringBoot使用Jasypt对YML文件配置内容进行加密(例:数据库密码加密)前言一、J

Java中有什么工具可以进行代码反编译详解

《Java中有什么工具可以进行代码反编译详解》:本文主要介绍Java中有什么工具可以进行代码反编译的相关资,料,包括JD-GUI、CFR、Procyon、Fernflower、Javap、Byte... 目录1.JD-GUI2.CFR3.Procyon Decompiler4.Fernflower5.Jav

Spring Boot 中正确地在异步线程中使用 HttpServletRequest的方法

《SpringBoot中正确地在异步线程中使用HttpServletRequest的方法》文章讨论了在SpringBoot中如何在异步线程中正确使用HttpServletRequest的问题,... 目录前言一、问题的来源:为什么异步线程中无法访问 HttpServletRequest?1. 请求上下文与线