面试 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利用docx4j+Freemarker生成word文档

《Java利用docx4j+Freemarker生成word文档》这篇文章主要为大家详细介绍了Java如何利用docx4j+Freemarker生成word文档,文中的示例代码讲解详细,感兴趣的小伙伴... 目录技术方案maven依赖创建模板文件实现代码技术方案Java 1.8 + docx4j + Fr

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

基于SpringBoot+Mybatis实现Mysql分表

《基于SpringBoot+Mybatis实现Mysql分表》这篇文章主要为大家详细介绍了基于SpringBoot+Mybatis实现Mysql分表的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录基本思路定义注解创建ThreadLocal创建拦截器业务处理基本思路1.根据创建时间字段按年进

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J