2024年150道高频Java面试题(二十七)

2024-04-14 09:04

本文主要是介绍2024年150道高频Java面试题(二十七),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

53. 什么是 Java 中的死锁?如何避免?

Java中的死锁是指两个或两个以上的线程因为竞争资源而造成的一种僵持状态,每个线程都在等待其他线程释放锁,但是这些锁又被其他线程持有,导致没有任何线程能继续执行下去,形成一种循环等待的局面。

死锁通常发生在以下四个条件同时满足时:

  1. 互斥条件:资源不能被多个线程共同使用,只能由一个线程独占。
  2. 占有且等待条件:线程至少持有一个资源,并且正在等待获取额外的资源,而该资源又被其他线程持有。
  3. 非抢占条件:线程持有的资源在未使用完毕前不能被其他线程强行抢占。
  4. 循环等待条件:存在一个线程与资源之间的循环等待链,每个线程都在等待下一个线程所持有的资源。

避免死锁的策略包括:

  1. 破坏死锁的四个必要条件之一:
    • 互斥条件无法破坏,因为它是资源使用的必要条件。
    • 通过一次性请求所有需要的资源来破坏占有且等待条件。
    • 允许线程剥夺已占有的资源,破坏非抢占条件。
    • 通过资源的有序分配来破坏循环等待条件,比如对所有资源进行编号,线程按编号顺序请求资源。
  2. 避免策略:
    • 设计合理的资源申请顺序,保证所有线程按照相同的顺序请求资源。
    • 减少资源的占有时间,尽快释放不再需要的资源。
    • 使用锁排序,确保所有线程都按照固定的全局顺序获取锁。
  3. 检测与恢复:
    • 通过资源分配图或者银行家算法来检测死锁,一旦检测到死锁,采取措施解除。
    • 通过线程回滚或者资源抢占来回滚到没有死锁的状态。
  4. 避免长时间锁:
    • 使用尝试获取锁的机制,如 tryLock() 方法,如果不能立即获取锁,则放弃。
    • 对锁进行超时处理,超时后自动放弃锁,减少资源占用时间。

以下是一个简单的死锁示例:

public class DeadlockDemo {public static void main(String[] args) {final Object resource1 = "Resource1";final Object resource2 = "Resource2";Thread t1 = new Thread(() -> {synchronized (resource1) {System.out.println("Thread 1: Locked resource 1");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (resource2) {System.out.println("Thread 1: Locked resource 2");}}});Thread t2 = new Thread(() -> {synchronized (resource2) {System.out.println("Thread 2: Locked resource 2");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (resource1) {System.out.println("Thread 2: Locked resource 1");}}});t1.start();t2.start();}
}

在上面的代码中,如果两个线程同时执行,并且分别获得了不同的锁,然后试图获取对方持有的锁,就可能导致死锁的发生。通过上述避免策略,我们可以重新设计代码,以避免这种潜在的问题。

54. synchronized 和 volatile 关键字有何区别?

synchronizedvolatile是Java中的两个关键字,它们被用于控制多线程访问共享资源时的同步问题。

  1. 作用域不同
    • synchronized可以修饰方法或代码块,它可以保证在同一时刻只有一个线程可以执行某个方法或代码块。
    • volatile只能用来修饰变量,确保对变量的读写操作对所有线程立即可见。
  2. 内存语义
    • 使用synchronized时,当线程进入同步代码块或方法,它会清空工作内存中的共享变量值,从主内存中重新读取。当线程退出同步代码块或方法时,它会将工作内存中的共享变量的最新值刷新回主内存。
    • volatile变量则是直接从主内存读取,对它的写操作也会直接写入主内存,保证了新值对其他线程的可见性。
  3. 操作粒度
    • synchronized的操作粒度比较粗,它锁定的是整个方法或代码块,在锁定期间其他线程无法访问同步资源。
    • volatile的操作粒度比较细,仅保证对单个变量的读写操作的可见性和有序性。
  4. 锁的影响
    • synchronized可以给方法或代码块加锁,导致线程在执行时会阻塞,等待锁的释放。
    • volatile不会造成线程的阻塞。
  5. 有序性
    • synchronized保证了操作的有序性,即进入同步代码块或方法的操作将在退出同步代码块或方法之前全部执行完毕。
    • volatile通过禁止指令重排优化,也保证了操作的有序性。

以下是一个使用synchronizedvolatile的示例:

public class Counter {// 使用volatile修饰共享变量private volatile int count = 0;// 使用synchronized修饰方法public synchronized void increment() {count++; // 这里隐式地使用了count变量}public int getCount() {return count; // 这里读取volatile变量}
}

在这个示例中,increment方法使用了synchronized,确保了在执行count++操作时,其他线程不能同时访问该方法。而变量count被声明为volatile,保证了count值的变化对其他线程是可见的。

总结来说,synchronized用于控制多线程访问资源的同步,关注的是操作的原子性和线程的互斥;而volatile关注的是变量访问的可见性和有序性,但不保证复合操作的原子性。
领【150 道精选 Java 高频面试题】请go公众号:码路向前 。

这篇关于2024年150道高频Java面试题(二十七)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Java Stream流与使用操作指南

《JavaStream流与使用操作指南》Stream不是数据结构,而是一种高级的数据处理工具,允许你以声明式的方式处理数据集合,类似于SQL语句操作数据库,本文给大家介绍JavaStream流与使用... 目录一、什么是stream流二、创建stream流1.单列集合创建stream流2.双列集合创建str

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 请求是一个高效且流行的方式。