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

相关文章

springboot集成easypoi导出word换行处理过程

《springboot集成easypoi导出word换行处理过程》SpringBoot集成Easypoi导出Word时,换行符n失效显示为空格,解决方法包括生成段落或替换模板中n为回车,同时需确... 目录项目场景问题描述解决方案第一种:生成段落的方式第二种:替换模板的情况,换行符替换成回车总结项目场景s

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq