2024年Java面试大全(持续更新)

1、Java 中 hashCode 和 equals 方法是什么?它们和 == 各有什么区别?

在 Java 中,hashCode 和 equals 方法都是 Object 类的方法。它们的作用分别如下:

hashCode 方法返回对象的哈希码,用于支持基于哈希表的集合,如 HashMap、HashSet 等。如果两个对象的 equals 方法返回 true,则它们的 hashCode 方法必须返回相同的值,反之则不需要。
equals 方法用于比较对象是否相等。默认情况下,equals 方法使用的是 == 操作符,即只有两个对象引用指向同一个对象时才会返回 true。但是,大部分情况下,我们需要重写 equals 方法来实现自己定义的相等规则。
两者之间的区别在于,hashCode 方法返回的是一个 int 类型的数值,而 equals 方法返回的是一个 boolean 类型的值。

hashCode 方法用于快速比较两个对象是否不同,因为如果它们的哈希码不同,那么它们肯定不相等。equals 方法则用于判断两个对象是否真正相等,这个判断比较复杂,需要根据对象的实际情况来定义。

另外,需要注意的是,== 操作符用于比较两个对象的引用是否相等,即它们是否指向同一个对象。而 equals 方法则用于比较两个对象的值是否相等。(String类对equals()方法进行了重写用户比较字符串的值是否相等。)

在 Java 中,对象的值比较往往需要根据对象的实际情况来定义,因此一般需要重写 equals 方法。

2、Spring 的两大核心概念是什么?简单讲一下你对它们的理解

初始
Spring的两大核心概念是控制反转IOC和面向切面编程AOP:

控制反转IOC:将创建对象和管理项目对象依赖关系的工作交给Spring,可以使开发者更专注于业务逻辑的开发,需要使用到对象时,可以直接在IOC容器中取,降低了代码的复杂度,提高了系统的可维护性。
面向切面编程AOP:开发者可以将一些通用代码,例如日志管理,事务等从业务中抽离出来,定义为切面,使其更易于管理,解耦合,提高了代码的可重用性。
想法
个人认为大家在背这些八股的时候,可以把知识都串联起来,类似思维导图一样,看到这里我们又能想到什么,层层递进。

再问问
那AOP是如何实现的呢?
(见 面试题挑战 Day3 JDK 动态代理和 CGLIB 动态代理的区别是什么?)
如果你简历上写了设计模式,那么这两个核心概念中有涉及到什么设计模式可以讲讲吗?
工厂设计模式:spring中使用了BeanFactory和ApplicationContext创建了Bean对象。
单例模式:在IOC中的对象默认都是单例的,可以通过配置文件修改。
代理模式:AOP就是基于动态代理的,如果对象实现了接口,使用JDK的动态代理,如果对象没有实现接口则使用CGLIB的动态代理。(这里可以暗示往这两个动态代理方面问,就又撞到前几天刷过的题了)
学识浅薄,应该还有其他,小伙伴们可以补充

3、死锁是什么?如何预防和避免死锁?

死锁是指两个或多个进程互相等待对方释放资源而陷入无限等待的状态,导致程序无法继续执行下去,称为死锁。

预防和避免死锁需要:

避免使用多个锁:在设计程序时,应尽量减少使用多个锁,或者在使用多个锁时,尽量将锁的持有时间缩短到最小。这可以减少死锁的概率。
避免嵌套锁:在使用嵌套锁时,需要注意锁的顺序,以避免不同线程获取锁的顺序不同而导致死锁。如果必须使用嵌套锁,可以使用统一的锁顺序来避免死锁。
使用超时机制:在获取锁时,可以设置一个超时时间,如果在指定时间内没有获取到锁,就放弃锁的获取,避免一直等待锁而导致死锁。
使用死锁检测和恢复机制:可以使用死锁检测机制来检测死锁的发生,并采取恰当的措施来解决死锁问题,比如终止一个进程或者回滚一个事务。
避免循环等待:在获取锁的时候,应该避免循环等待,即每个线程只能持有一个锁,而获取其他锁时必须先释放原有锁。


死锁是指两个或多个进程在执行过程中因争夺资源而造成的一种僵局,当进程处于死锁状态时,它们将无法继续执行,而只能相互等待,直到被外部的程序干预或自行放弃。

预防和避免死锁需要采取一些措施,包括:

避免资源独占:尽量避免一个进程在获得了某些资源后再次请求其他资源,而应该将所有需要的资源一次性申请到位。
避免资源持有和等待:当一个进程占用了一些资源并等待另一些资源时,其他进程就无法使用这些资源,容易引发死锁。因此,尽可能减少资源持有和等待时间。
避免资源互斥:有些资源在同一时间只能被一个进程占用,比如打印机、磁带机等,需要采用一些技术手段来避免资源互斥的问题。
引入资源剥夺策略:当一个进程请求的资源被其他进程占用时,可以采取剥夺资源的策略,即暂停占用该资源的进程,直到该资源被释放后再恢复该进程的执行。
引入进程抢占策略:当一个进程等待时间过长时,可以采取抢占其资源的策略,即中断正在执行的进程,强制释放其占用的资源。

篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记的【点击此处即可】即可免费获取

4、什么是反射机制?说说反射机制的优缺点、应用场景?

Java 反射机制是指在运行时动态地获取类的信息、创建对象以及调用对象的属性和方法的机制。Java 反射机制提供了运行时检查 Java 类型信息的能力,让 Java 程序可以通过程序获取其本身的信息。

Java 反射机制的优点:

    1、可以动态地获取类的信息,不需要在编译时就知道类的信息。
    2、可以动态地创建对象,不需要在编译时就知道对象的类型。
    3、可以动态地调用对象的属性和方法,可以在运行时动态地改变对象的行为。
Java 反射机制的缺点:

    1、由于反射是动态的,所以它的运行效率较低,不如直接调用方法或属性。
    2、由于反射是动态的,所以它会破坏 Java 的封装性,可能会使代码变得复杂和不稳定。
Java 反射机制的应用场景:

    1、动态代理。动态代理可以使用反射机制在运行时动态地创建代理对象,而不需要在编译时就知道接口的实现类。
    2、单元测试。JUnit 等单元测试框架可以使用反射机制在运行时动态地获取类和方法的信息,实现自动化测试。
    3、配置文件加载。许多框架(如 Spring)使用反射机制来读取和解析配置文件,从而实现依赖注入和面向切面编程等功能。

5、数据库索引是什么,有什么作用,什么场景适合使用索引?

数据库索引是一种数据结构,用于提高数据库表的查询效率。索引可以帮助数据库快速定位和检索存储在表中的数据,从而加快数据查询的速度。在数据量比较大时,使用索引可以极大地提高数据检索的效率。

索引的作用是通过构建一个额外的数据结构(B-tree、哈希表等)来加速数据的检索。它是在数据库表上创建的一种数据结构,它包含一些指向表中数据的指针,可以快速地定位到满足查询条件的数据行,从而提高查询效率。索引可以包含一个或多个列,可以使用单列索引、组合索引、全文索引等多种方式来创建。

适合使用索引的场景包括:

频繁查询的列,如主键、外键等。
经常作为查询条件的列,如WHERE、ORDER BY、GROUP BY 等语句中的列。
经常需要连接的列,如多表联合查询时的列。
数据量较大的表,通过索引可以加快数据检索速度。
索引的优点是可以提高数据库的查询速度,缩短数据检索的时间,提高系统的性能。但是索引也有一些缺点,包括:

占用额外的存储空间,增加了存储成本。
建立索引需要时间,增加了系统的开销。
数据库的更新操作(增删改)会导致索引的重建,影响系统的性能。
因此,需要根据实际情况进行索引的创建和使用,避免过度索引导致系统性能下降。

这题如果能举例你自己是如何在项目中应用索引的(比如检索用户消息)、或者说什么情况下你没有选择用索引的(比如性别字段),会很加分

6、HTTP 有哪些常见的状态码?

啥波一口诀 ( 也不用完全记忆 )
一信 二成 三重 四五败
1xx 一信
  提示信息,是协议处理的中间状态,还需要后续操作 ( 感觉一般也不会遇到 )
2xx 二成
200 : 常见的成功状态码
204 : 200状态码 - 无Body版
206 : 200状态码 - part版 ( 表示响应返回的body数据不是资源的全部 )
3xx 三重
301 : 永久重定向
302 : 301状态码 - 临时版 ( 临时重定向 )
304 : 不具有跳转意义,表示资源未修改,重定向到缓存 ( 304 Not Modified )
4xx 四败
客户端!!!
404 : 资源不存在或者未找到 ( 404 NOT FOUND )
400 : 请求报文有错误 ( 记忆方法: 400最小 发生在 Http 第一步(发送请求)中 )
401 : 请求需要认证
403 : 禁止访问 ( 403 Forbidden )
5xx 五败
服务端!! 
500 : 笼统错误码
502 : 服务器网关或者代理出现问题 ( 502 Bad GateWay )
503 : 服务器正忙,无法处理请求 ( 503 Unavailable )

7、Java 访问修饰符 public、private、protected,以及无修饰符(默认)的区别?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MiEl0MU-1683601393880)(.\面试题.assets\J2CEKIks-java.png)]

8、什么是分布式?为什么需要分布式?

布式是指在多台计算机上协同工作的系统,这些计算机通过网络连接在一起,共同完成一个任务。

分布式系统能够有效地解决单台计算机处理能力不足、系统容易宕机、数据存储容量有限等问题,同时能够提高系统的可靠性、可用性和性能,适用于数据量较大、并发量高、访问频繁的场景。此外,分布式系统还可以通过横向扩展的方式提高系统的性能和可靠性,同时降低单点故障的风险,提高了系统的可伸缩性,方便进行升级和维护。

在分布式系统中,由于数据和计算任务被分布在多台计算机上,不同计算机之间需要进行通信和协调,因此需要解决分布式一致性、负载均衡、故障恢复、数据共享和安全等问题,同时需要考虑数据的一致性和可靠性。因此,分布式系统的设计和实现比单机系统更加复杂和困难,需要考虑到多个因素的综合影响。

9、你是怎么做 MySQL 数据备份的?比如怎么恢复半个月前的数据?

MySQL 数据备份是一个非常重要的工作,保证数据的安全性和可靠性。备份数据的方式有很多种,以下是其中一种基本的备份和恢复方式:

一、备份 MySQL 数据库

我们可以使用 mysqldump 工具来备份 MySQL 数据库,该工具可以生成 SQL 脚本文件,包含数据库中所有表和数据的语句。在终端中运行以下命令:

mysqldump -u [username] -p [database_name] > [backup_file].sql

其中,[username] 是 MySQL 用户名,[database_name] 是需要备份的数据库名称,[backup_file].sql 是备份的文件名。

该命令会将 SQL 脚本文件导出到当前目录下。

二、恢复 MySQL 数据库

如果需要恢复之前备份的数据,可以运行以下命令:

mysql -u [username] -p [database_name] < [backup_file].sql

其中,[username] 是 MySQL 用户名,[database_name] 是需要恢复的数据库名称,[backup_file].sql 是备份的文件名。

该命令会将备份文件中的 SQL 语句执行,从而将数据恢复到指定的数据库中。

如果需要恢复半个月前的数据,可以选择备份文件中的某个时间点之前的数据,并使用以上方法进行恢复。

此外,还有其他的备份方式,如使用 MySQL 自带的 mysqlbinlog 工具进行增量备份,或使用第三方备份软件进行备份。根据实际需求选择合适的备份方式,并将备份文件存放在可靠的位置。

 篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记的【点击此处即可】即可免费获取

10、什么是消息队列?消息队列有哪些应用场景?

消息队列是一种用于异步通信的机制,用于在不同的应用程序之间传递消息。消息队列通常由消息生产者、消息队列和消息消费者三部分组成。

消息生产者将消息发送到消息队列中,而消息消费者则从消息队列中接收消息。消息队列负责存储和管理消息,确保消息传递的可靠性和稳定性。在实现过程中,消息队列还会提供一些额外的功能,如消息过滤、消息路由、消息持久化等。

消息队列的特点:

    异步通信:消息生产者和消息消费者之间采用异步通信模式,发送方无需等待接收方的响应即可继续执行。
    解耦合:消息队列可以将消息生产者和消息消费者解耦合,使得它们之间的关系更加灵活。
    可靠性:消息队列通常会提供一些保证消息传递可靠性的机制,如消息持久化、重试机制等。
    缓冲:消息队列可以缓冲来自多个消息生产者的消息,使得消息消费者可以按照自己的节奏进行消费,从而有效地平衡生产者和消费者之间的处理速度。		
消息队列的应用:

    异步任务处理:通过将任务发送到消息队列中,异步处理任务,提高系统的并发性能和吞吐量。
    解耦合系统:将不同的业务逻辑拆分成不同的服务,通过消息队列实现服务之间的通信,提高系统的可维护性和可扩展性。
    流量削峰:将流量通过消息队列分散到不同的服务中,避免单个服务被高并发流量打垮。
    日志收集:通过将日志消息发送到消息队列中,将日志收集和分析与业务逻辑解耦合,提高系统的可靠性和可维护性。
    应用解耦:将不同的应用程序通过消息队列进行集成,实现应用之间的解耦合和数据交换。

11、设计模式是什么?为什么要学习和使用设计模式?

设计模式是指在软件开发中经常遇到的一些重复性问题,通过对这些问题的总结、抽象、归纳和提炼,得到的一些解决问题的通用方案。学习和使用设计模式可以帮助开发人员提高代码的可重用性、可维护性、可扩展性和可读性,从而提高开发效率和代码质量。

设计模式的学习和使用,需要结合实际的业务场景进行理解和应用。以下是一些常见的现实业务场景和对应的设计模式:

工厂模式:当需要创建多种具有相同特征的对象时,使用工厂模式可以将对象的创建与业务逻辑分离,降低代码的耦合度。 例如,在电商平台上,不同种类的商品都需要进行库存管理和订单管理,可以使用工厂模式来创建对应的库存管理器和订单管理器。
单例模式:当需要确保系统中某个类只有一个实例时,可以使用单例模式,保证全局唯一性,避免资源的浪费。 例如,在 Web 应用中,有时需要保证所有请求都使用同一个数据库连接,可以使用单例模式来实现数据库连接池。
观察者模式:当一个对象的状态发生改变需要通知其他对象时,可以使用观察者模式,将对象的状态与业务逻辑分离,提高系统的灵活性和可扩展性。 例如,在多人在线游戏中,玩家的行为会影响其他玩家的状态,可以使用观察者模式来实现游戏中的事件处理和状态同步。
策略模式:当需要在运行时根据不同的情况采用不同的算法时,可以使用策略模式,将算法与业务逻辑分离,提高代码的可维护性和扩展性。 例如,在电商平台上,可以使用策略模式来实现不同的促销策略,例如满减、打折等。
面试官问到这个问题,可能想了解面试者是否熟悉常见的设计模式,并能够结合实际业务场景进行理解和应用,以提高代码质量和开发效率。同时,也想了解面试者是否有足够的设计能力和经验,能够在实际项目中使用设计模式来解决问题。

12、一条 SQL 语句在 MySQL 中的执行过程是怎样的?

在 MySQL 中,一条 SQL 语句的执行过程通常可以分为以下几个步骤:

词法分析和语法分析:MySQL 的 SQL 解析器会对输入的 SQL 语句进行词法分析和语法分析,以确定语句的结构和语法是否正确。
查询优化:MySQL 会对 SQL 语句进行优化,以确定最优的执行计划。在这个过程中,MySQL 会考虑许多因素,例如索引、表连接、统计信息等,以找到执行查询的最有效方式。
查询执行:在查询优化后,MySQL 开始执行查询,读取和处理数据。在执行过程中,MySQL 会根据查询中所涉及的表和列等信息,从磁盘中读取相应的数据,并进行计算和过滤操作。
结果返回:最后,MySQL 会将查询结果返回给客户端,完成整个查询过程。
需要注意的是,实际的执行过程可能会因为多种因素而不同,例如数据量、硬件配置等。另外,在并发环境下,多个查询可能会同时进行,需要使用锁和事务等机制来保证数据的一致性和正确性。

27、什么是 IOC,简单讲一下 Spring IOC 的实现机制?

什么是IOC容器,以及IOC的创建过程
	1、基本概念
        1、IOC(Inverse Of Controll,控制反转):就是原来代码里面需要自己手动创建的对象,依赖,反转给Spring来帮忙实现。我们需要创建一个容器,同时需要一种描述来让容器知道要创建的对象与对象之间的关系。
        2、在Spring中BeanFactory就是IOC容器,在Spring初始化的时候,创建容器,并将需要创建对象和对象的关系(xml,注解)通过BeanDefinitionReader加载到BeanDefinition中并保存在BeanDefinitionMap中,然后再由IOC容器创建bean对象.
    2、两种bean的注册方式
        方法1:通过@Bean+@Configuration的方式直接定义要创建的对象与对象的关系
        方式2:通过@Component定义类,这种方式必须使用@ComponetScan定位Bean扫描路径
    3、IOC的创建
        1、在Spring中BeanFactory就是IOC容器,在Spring初始化的时候,创建容器,并将需要创建对象和对象的关系(xml,注解)通过BeanDefinitionReader加载到BeanDefinition中并保存在BeanDefinitionMap中,在这个过程中会让BeanDefinitionProcesser(Bean的定义信息的后置处理器)进行增强,然后再由IOC容器创建bean对象.
    4、Bean的生命周期(面试官顺着问题往下问的拓展)
        1、bean的实例化:spring启动后,会查找和加载需要被spring管理的Bean,并且实例化
        2、bean的属性注入(bean的初始化):bean被实例化后将Bean的引入河值注入到bean的属性中
            1、查看是否调用一些aware接口,比如BeanFactoryAware,BeanFactoryAware,ApplicationContextAware接口,分别会将Bean的名字,BeanFactory容器实例,以及Bean所在用的上下文引用传入给Bean
            2、在初始化之前,会查看是否调用了BeanPostProcessor的预初始化方法,可以对bean进行扩展
        3、调用InitializingBean的afterPropertiesSet()方法:如果Bean实现了InitializingBean接口,spring将调用他们的afterPropertiesSet()方法,类似的,如果Bean使用init-method生命了初始化方法的话,这个方法也会被调用。
        4、初始化成功之后,会查看是否调用BeanPostProcessor的初始化后的方法:如果Bean实现了BeanPostProcessor接口,spring就将调用他们的postprocessAfterInitialization()方法。可以对bean进行扩展
        5、bean的正常使用:可以被应用程序正常使用了,他们将驻留在上下文中,直到应用的上下文被销毁
        6、bean的销毁:调用DisposableBean的destory()方法:如果Bean实现DisposableBean接口,spring将用他的destory()方法,相同的,如果Bean使用了destory-method生命销毁方法,该方法也会被调用。(但由于bean也分为单例和多例,单例bean会随着IOC容器的销毁而销毁,多例的bean不会随着IOC容器的销毁而销毁,他是通过JVM里面的垃圾回收器负责回收)

13、并发和并行有什么区别?同步和异步有什么区别?

并发和并行是两个计算机领域中经常被提到的概念,它们的含义有所不同。

1、并发(Concurrency):指的是系统中同时存在多个正在执行的任务,并且这些任务之间可能会相互影响。并发通常用来处理多个任务共享资源的情况。在单核 CPU 上,多个任务会轮流使用 CPU 时间片,表现为看似同时执行的情况,但实际上只有一个任务正在执行。
2、并行(Parallelism):指的是系统中同时存在多个并且相互独立的任务,并且这些任务可以在多个处理器上同时执行,真正意义上的同时处理多个任务。
3、同步(Synchronous):指的是程序按照代码的顺序执行,一行一行地执行,直到当前行执行完成后才能继续执行下一行。同步通常会阻塞调用者,直到任务完成才能返回。
4、异步(Asynchronous):指的是程序在执行某个任务时,不会一直等待任务完成,而是继续执行下一行代码,当任务完成后再进行相应的处理。异步通常不会阻塞调用者,可以提高系统的并发性能。
总的来说,"并发"和"并行"是针对多个任务的执行方式,"同步"和"异步"是针对任务执行的阻塞方式和返回方式。在实际应用中,可以根据不同的需求来选择合适的并发和同步方式,以提高系统的性能和可靠性。

14、String 和 StringBuffer、StringBuilder 的区别是什么?

String 和 StringBuffer/StringBuilder 是 Java 中两种不同的字符串处理方式,主要的区别在于 String 是不可变的(immutable)对象,而 StringBuffer 和 StringBuilder 则是可变的(mutable)对象。


String 对象一旦被创建,就不可修改,任何的字符串操作都会返回一个新的 String 对象,这可能导致频繁的对象创建和销毁,影响性能。而 StringBuffer 和 StringBuilder 允许进行修改操作,提供了一种更高效的字符串处理方式。


StringBuffer 和 StringBuilder 的主要区别在于线程安全性和性能方面。StringBuffer 是线程安全的,所有方法都是同步的,因此可以被多个线程同时访问和修改。而 StringBuilder 不是线程安全的,适用于单线程环境下的字符串处理,但是相比于 StringBuffer,StringBuilder 具有更高的性能。


因此,当字符串处理需要频繁修改时,建议使用 StringBuffer 或 StringBuilder;而当字符串处理不需要修改时,可以使用 String。

15、MySQL 中的索引是怎么实现的?B+ 树是什么,B 树和 B+ 树的区别,为什么 MySQL 要用 B+ 树?

MySQL 中的索引是通过 B+ 树实现的。B+ 树是一种多叉树,它可以将数据按照一定的顺序组织起来,从而提高查询效率。


B+ 树与 B 树的区别在于,B+ 树的所有数据都存储在叶子节点上,而非叶子节点只存储索引,这样可以提高数据查询效率。B+ 树的叶子节点之间使用指针相连,这样可以实现区间查找,也就是说,可以快速定位某个区间内的数据。

MySQL 之所以采用 B+ 树作为索引的实现方式,主要是因为 B+ 树具有以下优点:

    1、能够支持高效的范围查找和排序。
    2、叶子节点之间使用指针相连,能够支持高效的区间查询。
    3、B+ 树具有较高的数据密度,可以减少磁盘 I/O 次数,提高查询效率。
    4、B+ 树对于插入和删除操作也比较高效。
在 MySQL 中,B+ 树的实现主要是通过 InnoDB 存储引擎来实现的。InnoDB 存储引擎中的索引主要有聚簇索引和辅助索引两种类型,聚簇索引是根据主键创建的索引,而辅助索引是根据非主键列创建的索引。对于辅助索引,MySQL 中会同时创建一个对应的聚簇索引,这样可以提高查询效率。

16、Spring 框架中都用到了哪些设计模式?

Spring 框架中使用了许多设计模式,以下列举一些比较重要的:

    1、单例模式:Spring 的 Bean 默认是单例模式,通过 Spring 容器管理 Bean 的生命周期,保证每个 Bean 只被创建一次,并在整个应用程序中重用。
    2、工厂模式:Spring 使用工厂模式通过 BeanFactory 和 ApplicationContext 创建并管理 Bean 对象。
    3、代理模式:Spring AOP 基于动态代理技术,使用代理模式实现切面编程,提供了对 AOP 编程的支持。
    4、观察者模式:Spring 中的事件机制基于观察者模式,通过 ApplicationEventPublisher 发布事件,由 ApplicationListener 监听事件,实现了对象间的松耦合。
    5、模板方法模式:Spring 中的 JdbcTemplate 使用了模板方法模式,将一些固定的流程封装在父类中,子类只需实现一些抽象方法即可。
    6、策略模式:Spring 中的 HandlerInterceptor 和 HandlerExecutionChain 使用了策略模式,允许开发者自定义处理器拦截器,按照一定顺序执行。
    7、责任链模式:Spring 中的过滤器和拦截器使用了责任链模式,多个过滤器和拦截器按照一定顺序执行,每个过滤器和拦截器可以拦截请求或者响应并做出相应的处理。
总之,Spring 框架中充分利用了许多设计模式,提供了良好的扩展性和灵活性,降低了代码的耦合度,提高了代码的可维护性。

17、MySQL 事务有哪些隔离级别、分别有什么特点,以及 MySQL 的默认隔离级别是什么?

MySQL 事务有四种隔离级别:

    1、读未提交(Read Uncommitted):事务可以读取未提交的数据,可能会读到脏数据,会导致幻读、不可重复读、脏读等问题;
    2、读已提交(Read Committed):只能读取已经提交的数据,可以避免脏读问题,但是可能会遇到不可重复读、幻读问题;
    3、可重复读(Repeatable Read):保证同一个事务中多次读取同一数据的结果是一致的,避免了脏读和不可重复读问题,但是可能会遇到幻读问题;
    4、序列化(Serializable):最高的隔离级别,可以避免所有并发问题,但是并发性能非常低,开销很大。
MySQL 的默认隔离级别是可重复读(Repeatable Read)。

其中,脏读指一个事务读到了另一个事务未提交的数据,不可重复读指同一个事务多次读取同一数据得到不同结果,幻读指同一个事务前后读取的数据集合不一致。

在实际使用中,应该根据具体情况选择合适的隔离级别,权衡数据的一致性和并发性能。

18、Redis 的单线程模型,IO 多路复用是什么?

Redis是一个基于内存的高性能键值数据库,其单线程模型是Redis的核心之一。Redis采用单线程模型来处理客户端请求,即一个Redis进程中只有一个线程来执行所有的请求,所有的请求都按照顺序执行。这种单线程模型的好处是可以避免多线程间的上下文切换,同时避免了多线程带来的竞争条件和死锁等问题,从而提高Redis的性能。

为了提高IO效率,Redis采用了IO多路复用技术。IO多路复用是指通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读或写就绪),能够通知程序进行相应的读写操作。Redis使用了epoll作为IO多路复用的技术实现,在一个线程中维护多个客户端的连接,并通过epoll实现对多个socket的监听和管理。

在Redis中,客户端请求首先被接受并存储在一个队列中,然后由Redis的单个线程从队列中获取请求并处理,处理完成后将响应发送给客户端。当Redis需要从外部读取数据时,采用异步IO方式发送读请求,然后将当前请求挂起,等待数据读取完成后再继续执行。

总的来说,Redis的单线程模型和IO多路复用技术是Redis高性能的关键所在,其通过避免多线程带来的性能损失和采用高效的IO多路复用技术来提高IO效率,从而使Redis在高并发和高负载下表现出色。niz

19、什么是 BIO、NIO、AIO?

BIO、NIO、AIO 是 Java 中常用的 I/O 模型,它们都是针对网络编程中 I/O 操作的不同实现方式。

BIO,全称 Blocking I/O,也称为同步阻塞 I/O。BIO 是最早的 I/O 模型,它是一种阻塞式的 I/O 模型,即当应用程序调用 I/O 操作时,该操作会一直阻塞线程直到操作完成,这会导致 I/O 性能低下。BIO 适用于连接数较小的场景,例如单线程的服务器模型。

NIO,全称 Non-Blocking I/O,也称为同步非阻塞 I/O。NIO 是一种同步非阻塞的 I/O 模型,它的核心是 Selector 和 Channel,利用 Selector 监听多个 Channel 上的事件,当一个 Channel 上的事件到达时,它会被 Selector 转发给注册在这个 Selector 上的其他 Channel,这样可以用一个线程来处理多个请求,提高了 I/O 的效率。NIO 适用于连接数多、连接时间短的场景,例如实时聊天室、在线游戏等。

AIO,全称 Asynchronous I/O,也称为异步非阻塞 I/O。AIO 是 JDK1.7 引入的 I/O 模型,它的特点是异步处理 I/O 操作,当操作完成时会通知应用程序,相比于 NIO 的同步非阻塞 I/O,AIO 无需通过轮询操作完成状态,从而提高了 I/O 的效率。AIO 适用于连接数多、连接时间长的场景,例如 HTTP 长连接、文件操作等。

面试官问到这个问题,可能想了解你对 Java 中不同的 I/O 模型的了解程度,以及你能否根据不同的业务需求选择合适的 I/O 模型。同时,他可能还想了解你在实际开发中使用过哪些 I/O 模型,以及它们的应用场景。

 篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记的【点击此处即可】即可免费获取

20、意向锁是什么?有什么作用?它是表级锁还是行级锁?

意向锁(Intention Lock)是 InnoDB 存储引擎中的一种锁机制,它是一种表级锁,用于提高事务并发性,减少锁冲突。

意向锁分为意向共享锁(IS)和意向排他锁(IX),它们都是表级锁,IS 锁表示事务想要对表进行读操作,IX 锁则表示事务想要对表进行写操作。当一个事务请求获取某一行的行级锁时,InnoDB 会根据事务所需要的锁类型(共享锁或排它锁),在对应的表上添加意向锁,以告诉其他事务该表已经被锁定了。

使用意向锁,可以提高锁定对象的访问效率,降低锁定冲突率,增加并发度,减少死锁的发生。

在实际的业务场景中,如果多个事务同时请求对同一张表进行操作,使用意向锁可以有效减少锁定冲突,提高事务并发性。面试官可能会想了解你对意向锁的理解以及在实际开发中的应用场景。

21、Spring、SpringMVC、SpringBoot 三者之间是什么关系?

Spring、Spring MVC 和 Spring Boot 是 Spring Framework 的三个重要组成部分,它们之间的关系可以概括为:

1、Spring 是一个开源的轻量级 Java 开发框架,它提供了丰富的基础设施和简化的编程模型,可以使 Java 开发变得更加简单、高效、灵活和可维护。
2、Spring MVC 是 Spring 框架中的一个模块,它是基于 MVC 设计模式的 Web 开发框架,可以帮助开发人员快速构建灵活可扩展的 Web 应用程序。
3、Spring Boot 是 Spring Framework 的另一个重要模块,它是一种快速开发框架,旨在简化 Spring 应用程序的搭建和部署。Spring Boot 提供了一个开箱即用的应用程序开发环境,可以自动配置许多常用的组件和库,从而简化开发过程,减少了配置文件的编写,使得开发人员可以更专注于业务代码的编写。
因此,可以将 Spring 看作是整个框架的核心,Spring MVC 是针对 Web 开发的模块,而 Spring Boot 则是提供快速开发和部署的工具。它们之间是一种嵌套的关系,即 Spring Framework 包含 Spring MVC,而 Spring Boot 又是在 Spring Framework 的基础上构建的。

37、Redis 基础类型中的 String 底层实现是什么?

Redis 中的 String 是一种简单的键值类型,支持存储字符串、整数和浮点数等数据类型。String 的底层实现是基于字节数组的动态字符串(Dynamic String),即 Redis 的 sds 数据结构。

通过采用 sds 数据结构作为 String 的底层实现,Redis 可以实现高效的字符串存储和操作,具有良好的扩展性和性能。

sds(Simple Dynamic String)是 Redis 自己实现的字符串类型,具有如下特点:

1、二进制安全:可以存储任意二进制数据,不会被误解释为字符串。
2、动态扩容:可以动态地扩展字符串的长度,避免了固定长度字符串的空间浪费和长度限制问题。
3、缓存长度:可以缓存字符串的长度信息,避免了频繁计算字符串长度的开销。
sds 的底层实现采用了类似于 C++ 中的 std::string 的方式,即使用一个 struct sds 结构体来表示动态字符串,该结构体包含如下字段:

1、len:表示字符串的长度。
2、free:表示字符串中未使用的空间大小。
3、buf:表示字符串实际存储的空间,即字节数组。

38、有哪些注解可以注入 Bean?@Autowired 和 @Resource 的区别?

在 Spring 框架中,常用的注入 Bean 的注解包括:

1、@Autowired:自动注入,按照类型自动装配,如果有多个同类型的 Bean,则需要通过 @Qualifier 指定具体的 Bean。
2、@Resource:Java 自带的注入方式,按照名称自动装配,默认是按照属性名称进行匹配,如果需要按照 Bean 的名称进行匹配,可以使用 @Resource(name="beanName")。
3、@Inject:和 @Autowired 类似,也是按照类型进行自动装配,但是 @Inject 注解是 JSR-330 提供的,而 5、@Autowired 注解是 Spring 框架提供的。
4、@Value:用于注入配置文件中的属性值,可以指定默认值。
5、@Component:用于声明一个 Bean,作用类似于 XML 中的 <bean> 标签。

39、请你介绍下 JVM 内存模型,分为哪些区域?各区域的作用是什么?

JVM 内存模型分为以下几个区域:

    1、程序计数器(Program Counter Register):每个线程都有自己的程序计数器,用于指示当前线程执行的字节码指令的行号,以便线程执行时能够回到正确的位置。
    2、虚拟机栈(JVM Stack):也称为 Java 方法栈,用于存储方法执行时的局部变量表、操作数栈、动态链接、方法出口等信息。每个线程在执行一个方法时,都会为该方法分配一个栈帧,并将该栈帧压入虚拟机栈,当方法执行完毕后,虚拟机会将其出栈。
    3、本地方法栈(Native Method Stack):与虚拟机栈类似,用于存储本地方法的执行信息。
    4、堆(Heap):用于存储对象实例,是 JVM 中最大的一块内存区域。堆是被所有线程共享的,当创建一个新对象时,对象实例存储在堆中,堆中存储的对象实例都有一个标记用于标记对象是否存活。垃圾回收器会周期性地回收那些没有被标记为存活的对象。
    5、方法区(Method Area):用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区也是被所有线程共享的。
    6、运行时常量池(Runtime Constant Pool):是方法区的一部分,用于存储编译期间生成的各种字面量和符号引用,这些内容在类加载后进入常量池中。
    其中,程序计数器、虚拟机栈、本地方法栈是线程私有的,堆、方法区、运行时常量池是线程共享的。

40、Linux 中的硬链接和软连接是什么,二者有什么区别?

在 Linux 文件系统中,硬链接(hard link)和软链接(symbolic link)都是一种文件链接的方式,可以用于将一个文件链接到另一个文件上。它们的主要区别在于创建方式、所占空间和使用限制等方面。

硬链接是通过在文件系统中创建一个新的目录项(directory entry)指向同一文件 inode 的位置来实现的。因为硬链接实际上是指向同一 inode,所以如果原文件被删除,硬链接依然能够访问到原文件的内容。硬链接的使用范围比较受限,因为硬链接只能指向同一个文件系统内的文件,不能跨文件系统创建。

软链接是通过在文件系统中创建一个新的文件来实现的,该文件中包含指向另一个文件的路径。软链接可以跨文件系统创建,并且可以指向任何类型的文件。但是,当原文件被删除时,软链接将会失效。

总的来说,硬链接更加高效,因为它只是添加了一个新的目录项,所以对磁盘空间的消耗比软链接要小。但是,硬链接不能跨文件系统,所以在实际应用中需要根据具体的需求来选择使用哪种链接方式。

41、给出IPv4地址求出兼容的IPv6地址

135.75.43.52 按十六进制算出即87.4B.2B.34,

而87.4B.2B.34串地址一组还是8位,所以需要两组v4地址合成v6地址,

再把前96位补零,它可以被转化为

0000:0000:0000:0000:0000:0000:874B:2B34或者::874B:2B34。

以小数点为划分,每个除以10,结果是第一位然后余数是第二位【135/16=8余7】,前两个小数点数把中间小数点去删掉,最前面补::

42、给出子网掩码,求最大可以连接多少台主机

先将子网掩码转换成二进制,如:255:255:240:0转换成二进制为 11111111:11111111:11110000:00000000 然后计算有多少个0,上面有12个零,然后因为有两台主机需要分配给网络地址、广播地址 所以 最大连接主机为 2的12次方-2=4094台

43、给出非连通无向图的边数,求至少需要多少个顶点

公式:先看有多少条边然后利用公式连通图为:n(n-1)/2 = 边数点  非连通则需多加一个点 n+1 顶点

44、强引用,软引用,弱引用和虚引用的区别与用法

1.强引用
特点:我们平常典型编码Object obj = new Object()中的obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。 当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略。

应用场景:项目中到处都是。

2.软引用
特点:软引用通过SoftReference类实现。 软引用的生命周期比强引用短一些。只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象:即JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。后续,我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。

应用场景:软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。

具体实例:图片缓存框架中,“内存缓存”中的图片是以这种引用来保存,使得JVM在发生OOM之前,可以回收这部分缓存。

3.弱引用
特点:弱引用通过WeakReference类实现。 弱引用的生命周期比软引用短。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。由于垃圾回收器是一个优先级很低的线程,因此不一定会很快回收弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。【弱引用在很多地方都有用到,比如ThreadLocal、WeakHashMap。】

应用场景:弱应用同样可用于内存敏感的缓存。

具体实例:在静态内部类中,经常会使用虚引用。例如,一个类发送网络请求,承担callback的静态内部类,则常以虚引用的方式来保存外部类(宿主类)的引用,当外部类需要被JVM回收时,不会因为网络请求没有及时回来,导致外部类不能被回收,引起内存泄漏。

4.虚引用
特点:虚引用也叫幻象引用,通过PhantomReference类来实现。无法通过虚引用访问对象的任何属性或函数。幻象引用仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

看到一个比较有意思的举例:

    1、强引用就像大老婆,关系很稳固。
    2、软引用就像二老婆,随时有失宠的可能,但也有扶正的可能。
    3、弱引用就像情人,关系不稳定,可能跟别人跑了。
    4、幻像引用就是梦中情人,只在梦里出现过。
    
    参考文章:https://blog.csdn.net/m0_45406092/article/details/108576301
    
    


 篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记的【点击此处即可】即可免费获取

45、java弱引用能转换为强引用吗?

弱引用可以被转化为强引用

import java.lang.ref.WeakReference;

public class WeakReferenceTest {

    public static void main(String[] args) throws InterruptedException {
        WeakReference<String> sr = new WeakReference<String>(new String("hello"));

        System.out.println(sr.get());
        String abc = sr.get(); // 被改为强引用
        System.gc(); // 通知JVM的gc进行垃圾回收

        Thread.sleep(2000); // gc可能存在延迟,确保下次打印之前一定先执行gc
        System.out.println(sr.get());
    }
}

46、MySQL的关键字执行顺序

from => on => join(left join、 right join、…)=> where => group by => having =>select=>distinct=>union(union all)=>order by=>limit
  • 1

47、synchronized是否具有传递性(父类方法加了synchronized,子类方法是否也继承)

synchronized关键字不具备继承性,父类定义了方法A用synchronized修饰,子类继承父类,同样调用方法A,此时子类调用A是不具备同步功能的,需要添加synchronized关键字。主要是因为:synchronized非函数签名,因此无法被继承,所以无法保证子类调用同步.


1、synchronized修饰实例方法,这样的含义是锁住当前实例对象
2、synchronized修饰静态方法,这样的含义是锁住当前类对象
3、synchronized锁住代码块,对指定的对象加锁
4、synchronized是可以重入锁,无法被中断,而且在代码块中执行wait notify notifyAll,必须是锁住的对象才可以
5、synchronized不具备继承特性

48、最长连续序列

题目:给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 :

输入:nums = [100,4,200,1,3,2]

输出:4

解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

分析:这道题要求求最长连续序列,并给定了O(n)复杂度限制,我们的思路是,使用一个集合HashSet存入所有的数字,然后遍历数组中的每个数字,如果其在集合中存在,那么将其移除,然后分别用两个变量pre和next算出其前一个数跟后一个数,然后在集合中循环查找,如果pre在集合中,那么将pre移除集合,然后pre再自减1,直至pre不在集合之中,对next采用同样的方法,那么next-pre-1就是当前数字的最长连续序列,更新res即可。这里再说下,为啥当检测某数字在集合中存在当时候,都要移除数字。这是为了避免大量的重复计算,就拿题目中的例子来说吧,我们在遍历到4的时候,会向下遍历3,2,1,如果都不移除数字的话,遍历到1的时候,还会遍历2,3,4。同样,遍历到3的时候,向上遍历4,向下遍历2,1,等等等。如果数组中有大量的连续数字的话,那么就有大量的重复计算,十分的不高效,所以我们要从HashSet中移除数字

49、有一个文件里面存储了全国人口的年龄,年龄之间用逗号分隔,需要统计每个年龄的人数,年龄范围0~110 (没什么难度主要就是考验一下变成基本功,看看没有ide的情况能否写出来,使用io记得捕捉异常即可)

import java.util.*;

public class Test {
    public static Object count(String filePath) {
        try (BufferedReader br = new BufferedReader(new FileReader(new File(filePath)))) {
            String info = br.readLine();
            String[] ages = info.split(",");
            
            long[] result = new long[111];
            
            for (String age : ages) {
                int index = Integer.parseInt(age);
                result[index] = result[index]++;
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;
    }
}

50、如何使用 Redis 实现一个排行榜?

Redis实现排行榜是Redis中一个很常见的场景,主要使用的是ZSet进行实现,下面是为什么选用ZSet:

有序性:排行榜肯定需要实现一个排序的功能,在Redis中有序的数据结构有List和ZSet;
支持分数操作:ZSet可以对集合中的元素进行增删改查操作,十分贴合排行榜中用户分数动态变化的场景,而List并不能针对分数进行操作,只有其中的value进行操作;
支持范围查询:ZSet可以按照分数进行范围查询,如排行榜中的Top10需求就可通过该特性进行实现;
支持去重:由于ZSet属于Set的特殊数据结构,因此同样拥有Set不可重复的特性,对于排行榜中不可出现重复项的需求也十分贴合,而List只能手动去重。
因此选择ZSet实现排行榜相对于List实现会更合适和高效。
# 添加示例数据
ZADD scores 90 "张三"
ZADD scores 85 "李四"
ZADD scores 95 "王五"
ZADD scores 92 "赵六"
# 查询排名前3的学生信息
ZRANGE scores 0 2 WITHSCORES
# 查询排名前3的打印
1) "王五"
2) "95"
3) "赵六"
4) "92"
5) "张三"
6) "90"
# 删除学生“李四”的成绩信息
ZREM scores "李四"
// 添加学生成绩
public void addScore(String name, int score) {
    redisTemplate.opsForZSet().add("scores", name, score);
}

// 查询排名前N的学生成绩
public List<Map.Entry<String, Double>> getTopScores(int n) {
    return redisTemplate.opsForZSet().reverseRangeWithScores("scores", 0, n - 1)
            .stream()
            .map(tuple -> new AbstractMap.SimpleEntry<>(tuple.getValue(), tuple.getScore()))
            .collect(Collectors.toList());
}

// 删除某个学生的成绩
public void removeScore(String name) {
    redisTemplate.opsForZSet().remove("scores", name);
}

51、什么是网关,网关有哪些作用?

网关(Gateway)是连接两个或多个不同网络的设备,可以实现协议的转换、数据的转发和安全策略的实现等功能。简单来说,网关是设备与路由器之间的桥梁,由它将不同的网络间进行访问的控制,转换,交接等等。

常见的网关有应用网关、协议网关、安全网关等。

网关的作用如下:

实现协议的转换:不同网络之间通常使用不同的协议,通过网关可以实现协议的转换,使得不同网络之间能够相互通信。
    1、提供数据转发功能:网关可以对传输的数据进行过滤、路由、转发等处理,确保数据的可靠传输。
    2、实现安全策略:网关可以对传输的数据进行加密、认证、授权等操作,保证数据的安全性和可靠性。
    3、提供缓存功能:网关可以将一部分数据缓存起来,提高数据的访问速度和响应性能。
    4、支持负载均衡:网关可以将请求分配到不同的服务器上,实现负载均衡,提高系统的可用性和性能。
    5、实现访问控制:网关可以对访问进行控制,防止未授权的访问和攻击,提高系统的安全性

 篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记的【点击此处即可】即可免费获取

52、线程的生命周期是什么,线程有几种状态,什么是上下文切换?

1、六种状态
Java中有六种状态:新建状态(New)、就绪状态(Runnable)、阻塞状态(Blocked)、等待状态(Waiting)、超时等待(Timed_Waiting)、终止状态(Terminated)

    1、NEW:初始状态,线程被创建出来但没有被调⽤ start() 。
    2、RUNNABLE:运⾏状态,线程被调⽤了 start() 等待运⾏的状态。
    3、BLOCKED:阻塞状态,需要等待锁释放。
    4、WAITING:等待状态,表示该线程需要等待其他线程做出⼀些特定动作(通知或中断)。
    5、TIME_WAITING:超时等待状态,可以在指定的时间后⾃⾏返回⽽不是像 WAITING 那样⼀直等待。
    6、TERMINATED:终⽌状态,表示该线程已经运⾏完毕。
2、五种状态

从操作系统层面的划分,线程有五种状态:新建、就绪、运行、阻塞和死亡状态。

    1、新建状态(New) : 新创建了一个线程对象
    2、就绪状态(runnable) : 线程对象创建后,其他线程调用了该对象的 start 方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权
    3、运行状态(Running) : 就绪状态的线程获取了 CPU,执行程序代码
    4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态
    5、死亡状态(Dead) :线程执行完了或者因异常退出了 run 方法,该线程结束生命周期。
3、阻塞情况又分为三种:

    1、等待阻塞:运行的线程执行 wait 方法,该线程会释放占用的所有资源,JVM会把该线程放入 "等待池"中,进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用 notify 或者 notifyAll 方法才能被唤醒,wait 是object 类的方法。
    2、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入 "锁池"中。
    3、其他阻塞:运行的线程执行 sleep 或者 join 方法,或者发出了 I/O请求时,JVM 会把该线程设置为阻塞状态。当 sleep 状态超时、join 等待线程终止或者超时、或者 I/O处理完毕时,线程重新转入就绪状态。 sleep 是 Thread 类

3、上下文切换

    线程的状态变化通常是由操作系统进行管理和控制的,当线程状态发生变化时,需要进行上下文切换。
    
    上下文切换是指将当前线程的状态保存下来,并将CPU资源切换到另一个线程上运行的过程。上下文切换需要花费一定的时间和系统资源,因此,线程的上下文切换次数要尽量减少,以提高系统的性能。

53、MVCC 是什么?InnoDB 是如何实现 MVCC 机制的?

MVCC机制

我们先设定一个场景:

假设数据库表中存在一条记录row_old,这时事务A和事务B同时begin,事务A将该记录修改为了row_new,事务B读取行记录,事务A提交,事务B再次读取这条行记录。

本文中将使用该场景来分析“脏读”和“不可重复读”现象。

若事务B在A提交前读到row_new,即出现“脏读”现象;若事务B在A提交后读到row_new,即出现“不可重复读”现象。

但是,正常情况是,无论事务A是否提交,事务B读取该条记录,都只能读出row_old。

什么方法可以达到这种效果呢?可以很直观地想到,将事务A修改后的版本存起来。那么又有一系列问题,如何存,用什么结构来存?版本链便是为此而引入的。

版本链

版本链,实际上就是一条存储多个版本行记录的链表。数据库中的每一行数据都对应一个版本链。链表中每一个结点代表一个行记录。行记录中有两个重要的隐藏字段:

trx_id:记录修改成当前版本的事务编号;

roll_pointer:指向上一个版本的指针,即回滚指针。

版本链的最底层即为数据表中最原始的行记录,上层存储各个事务修改后的行记录,逐个用回滚指针相连接


还有一个问题,版本链是存储在哪的?没错,我们熟悉的undo log回滚日志就是用来存储版本链的 。

一致性视图

如果当前事务修改一条记录,这条更新过的记录被记录到版本链中,对于当前事务而言,由于自身事务id和版本链中最新一条行记录的trx_id相匹配,所以可以将其读取出来。但是对于其它事务而言,是不希望能读出这条记录的,而是希望它能顺着版本链,找出自己需要的版本的行记录。

那么如何找到正确的版本?这里涉及到一个快照机制。事务在执行select语句时,会生成一个一致性视图:read-view,相当于一个快照,记录正在活跃的事务的编号。

read-view里面包含一个数组,m_ids,该数组记录(产生快照的这一时刻)版本链中未提交的每个版本的trx_id组成的序列。同时,read-view还会记录一个最大已创建事务id,即 max_id,以及数组中最小id即 min_id。查询版本链时,会将行记录中的trx_id与read-view中的max_id、min_id、m_ids[]等进行比对。依据如下版本比对规则来进行比对。

版本链比对规则

如果trx_id小于min_id,说明该版本是已提交事务生成的,数据可见;

如果trx_id大于max_id,说明该版本是将来启动的事务生成的,数据不可见;

如果min_id<=trx_id<=max_id,就包括两种情况:

trx_id在m_ids数组中:表示这个版本是未提交事务生成的,数据不可见,本事务可见;

trx_id不在m_ids数组中:表示这个版本是已提交事务生成的,数据可见。

补充:删除的原理:

删除可以认为是update的特殊情况。假如要删除一行记录,会将版本链上最新一条记录复制一份,将行格式头信息中(record header)里面的(deleted flag)标志位置为true,表示当前记录已被删除。若顺着版本链访问到这条记录,(deleted flag)标志位为true,表示记录已删除,不返回数据。

54、Redis 的持久化机制有哪些?说说各自的优缺点和应用场景?

Redis 的持久化机制主要分为 RDB 和 AOF 两种。

RDB 持久化机制

RDB 持久化机制是指将 Redis 在内存中的数据以快照的形式写入磁盘中,可以手动或自动执行快照操作,将数据集的状态保存到一个 RDB 文件中。RDB 机制的优点在于:

    1、RDB 机制适合在数据集比较大时进行备份操作,因为它可以生成一个非常紧凑、经过压缩的数据文件,对于备份、恢复、迁移数据都很方便。
    2、RDB 机制在 Redis 重启时比 AOF 机制更快地将 Redis 恢复到内存中。
RDB 机制的缺点在于:

    1、RDB 机制可能会出现数据丢失,因为数据是周期性地进行备份,一旦 Redis 出现问题并且上一次备份之后还没有进行过数据变更,那么这部分数据将会丢失。
    2、RDB 机制会造成一定的 IO 压力,当数据集比较大时,进行备份操作可能会阻塞 Redis 服务器进程。
    AOF 持久化机制

AOF 持久化机制是指将 Redis 在内存中的操作命令以追加的形式写入到磁盘中的 AOF 文件,AOF 文件记录了 Redis 在内存中的操作过程,只要在 Redis 重启后重新执行 AOF 文件中的操作命令即可将数据恢复到内存中。AOF 机制的优点在于:

    1、AOF 机制比 RDB 机制更加可靠,因为 AOF 文件记录了 Redis 执行的所有操作命令,可以确保数据不丢失。
    2、AOF 机制在恢复大数据集时更加稳健,因为 AOF 文件记录了数据的操作过程,可以确保每一次操作都被正确地执行。
AOF 机制的缺点在于:

    1、AOF 机制生成的 AOF 文件比 RDB 文件更大,当数据集比较大时,AOF 文件会比 RDB 文件占用更多的磁盘空间。
    2、AOF 机制对于数据恢复的时间比 RDB 机制更加耗时,因为要重新执行 AOF 文件中的所有操作命令。
综上所述,RDB 适合用于数据集较大、备份、恢复数据和迁移数据等场景,AOF 适合用于数据可靠性要求高、数据恢复稳健等场景。

55、Ngnix 是什么?它有哪些应用场景?

Nginx(发音为“engine-x”)是一个高性能的开源Web服务器和反向代理服务器,可以处理大量的并发连接和请求。它使用事件驱动的异步架构和多线程设计,可以高效地处理并发请求,同时也支持反向代理、负载均衡、动态HTTP缓存、SSL/TLS终止、基于模块的扩展等功能。

Nginx 的应用场景非常广泛,以下是其中的几个:

    1、Web 服务器:Nginx 可以作为 HTTP 服务器,处理并发的静态请求和动态请求,并且可以支持负载均衡和缓存,为网站提供高性能和高可用性。
    2、反向代理服务器:Nginx 可以作为反向代理服务器,接收客户端请求并将其转发到后端服务器,同时也可以支持负载均衡和缓存。
    3、邮件代理服务器:Nginx 可以作为邮件代理服务器,支持 POP3、IMAP 和 SMTP 协议,并且可以支持 SSL/TLS 加密和反垃圾邮件功能。
    4、流媒体服务器:Nginx 可以作为流媒体服务器,支持 RTMP、HLS 和 DASH 协议,可以用于实现直播、点播和视频-on-demand(VoD)等场景。
总之,Nginx 具有高性能、可扩展性和可靠性等特点,被广泛应用于大型网站、互联网公司、云计算、视频流媒体、游戏等领域。

56、线性表的顺序存储结构是一种() 的存储结构,线性表的链式存储结构是一种顺序存取的存储结构。

随机存取  【存储跟存取不一样  存取是随机的 比如a[7][5]】

57、哪些Java中的流对象是字节流?

stream结尾都是字节流,reader和writer结尾都是字符流 两者的区别就是读写的时候一个是按字节读写,一个是按字符。 实际使用通常差不多。 在读写文件需要对内容按行处理,比如比较特定字符,处理某一行数据的时候一般会选择字符流。 只是读写文件,和文件内容无关的,一般选择字节流。

58、局部内部类

1、内部类不能被public、private、static修饰;

2、在外部类中不能创建内部类的实例;

3、创建内部类的实例只能在包含他的方法中;

4、内部类访问包含他的方法中的变量必须有final修饰;

5、外部类不能访问局部内部类,只能在方法体中访问局部内部类,且访问必须在内部类定义之后。

59、有一个用数组C[1…m]表示的环形队列,m为数组的长度。假设f为队头元素在数组中的位置,r为队尾元素的后一位置(按顺时针方向)。若队列非空,则计算队列中元素个数的公式应为?

分情况讨论:
1. 若f<r<=m, 则有r-f <m,即队尾没有超出边界,则为r-f
2. 若r<f<=m, r-f < 0, 即队尾超出边界m,那么应为m+r -f
综合两种情况,得到答案 (m+r-f) mod m

 篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记的【点击此处即可】即可免费获取

60、创建线程的方法

1.继承Thread类,重载run方法;
2.实现Runnable接口,实现run方法 

61、表达式(short)10/10.2*2运算后结果类型是

	首先,要注意是(short)10/10.2*2,而不是(short) (10/10.2*2),前者只是把10强转为short,又由于式子中存在浮点数,所以会对结果值进行一个自动类型的提升,浮点数默认为double,所以答案是double;后者是把计算完之后值强转short。
  • 1

62、Dubbo 是什么?是否了解过它的架构设计?

Dubbo是一个高性能、轻量级的开源Java RPC框架,可以用于构建分布式服务应用。

Dubbo的架构设计如下:

服务提供方:暴露服务的服务提供方。	
服务消费方:调用远程服务的服务消费方。
注册中心:服务注册与发现的中心。
监控中心:统计服务的调用次数和调用时间的监控中心。
配置中心:服务配置的中心化管理。
Dubbo的设计理念是面向接口代理的RPC框架。Dubbo的服务提供方将服务暴露在注册中心上,服务消费方通过注册中心发现服务并调用远程服务,Dubbo会自动将底层的通信细节和序列化过程封装起来,使得服务提供方和服务消费方可以像调用本地方法一样调用远程服务。Dubbo支持多种协议和序列化方式,并且提供了多种负载均衡和容错机制,具有很高的可扩展性和可定制性。

Dubbo的优点包括:
    1、高性能:Dubbo采用了多种优化手段,如线程池复用、请求响应式编程、异步执行等,以提高系统的并发能力和吞吐量。
    2、高可靠性:Dubbo提供了多种容错机制,如重试、熔断、降级等,以保证服务的可用性。
    3、易于扩展:Dubbo的设计理念是面向接口代理的RPC框架,支持多种协议和序列化方式,以满足不同的应用场景需求。
    4、易于集成:Dubbo提供了与Spring Framework、Spring Boot等常见开发框架的无缝集成,以方便开发者使用。
    Dubbo的应用场景包括:微服务架构、SOA架构、分布式系统、RPC调用等。

63、synchronized 关键字是什么,有什么作用?

synchronized 是 Java 中的一个关键字,用于实现线程同步。具体来说,synchronized 用于修饰方法或代码块,使得同一时刻只能有一个线程访问被修饰的代码,其他线程需要等待当前线程执行完毕后才能访问。

synchronized 主要用于解决多线程并发访问共享资源时出现的线程安全问题。如果多个线程同时访问一个共享资源,就会出现多个线程同时修改这个资源的情况,从而导致数据不一致等问题。而使用 synchronized 可以保证同一时刻只有一个线程访问该资源,从而避免了线程安全问题。

synchronized 的作用不仅限于线程同步,它还可以保证可见性和有序性,即保证在同一个锁上,一个线程修改了共享变量的值之后,另一个线程能够立即看到修改后的值,并且在多个线程执行顺序上保证了一致性。

需要注意的是,使用 synchronized 会带来一定的性能损失,因为每次进入同步块时都需要获得锁,这会增加线程的等待时间和上下文切换的开
  • 29
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值