java常见面试题

1.JVM内存结构原理

  1. 方法区(Method Area): 方法区是 JVM 的一部分,用于存储类的结构信息、运行时常量池、静态变量、即时编译器编译后的代码等。在 HotSpot JVM 中,方法区被称为永久代(Permanent Generation),但是在 JDK 8 中已经被移除,被元空间(Metaspace)所取代。

  2. 堆(Heap): 堆是 Java 程序运行时所分配的内存中最大的一块,用于存储对象实例和数组。堆被所有线程共享,而且在 JVM 启动时创建。堆的大小可以通过 JVM 参数来调节。

    堆又分为新生代和老年代: 比例1:2

    新生代:新生代分为Eden区、Survivor区(From区和To区) 比列8:2 新创建的对象存放到新生代(Eden)区,经过一次垃圾回收,存活的对象放入survivor区。

    老年代:老年代用于存放长时间存活的对象,通常是经过多次Minor GC仍然存活下来的对象,或者是大对象直接在老年代分配的

  3. 虚拟机栈(VM Stack): 每个线程在创建时都会有一个独立的虚拟机栈,用于存储局部变量、方法参数、方法返回值以及部分计算结果。每个方法在执行时都会创建一个栈帧,用于存储方法的局部变量表、操作数栈、动态链接、方法出口等信息。栈帧随着方法的调用和返回而入栈和出栈。

  4. 本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈类似,但是它用于执行 native 方法,即用 C 或 C++ 语言编写的方法。

  5. 程序计数器(Program Counter Register): 程序计数器是当前线程所执行的字节码的行号指示器。每个线程都有一个独立的程序计数器,用于记录当前线程正在执行的字节码指令地址或下一条即将执行的指令地址。在多线程环境下,程序计数器是线程私有的,不会发生线程间的共享。

  6. 直接内存(Direct Memory): 直接内存不是 JVM 运行时数据区的一部分,但是与堆内存密切相关。在 JDK 1.4 中引入了 NIO(New I/O)类库,其中包含了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式,可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。

2. 线程的实现方式,线程池的七大核心参数,拒绝策略

线程池的七大核心参数

  1. corePoolSize(核心线程数): 线程池中保持存活的线程数量,即使它们当前处于空闲状态。当提交任务到线程池时,如果线程池中的线程数小于 corePoolSize,将会创建一个新的线程来处理任务。

  2. maximumPoolSize(最大线程数): 线程池中允许存在的最大线程数。当提交任务到线程池时,如果当前线程数已经达到了 corePoolSize,并且阻塞队列已满,且当前线程数小于 maximumPoolSize,将会创建一个新的线程来处理任务。

  3. keepAliveTime(线程空闲时间): 当线程池中的线程数量超过 corePoolSize,并且处于空闲状态时,这些空闲线程在被回收之前需要等待的时间。

  4. unit(时间单位): keepAliveTime 参数的时间单位,可以是秒、毫秒、微秒等。

  5. workQueue(阻塞队列): 用于保存等待执行的任务的阻塞队列。当线程池中的线程数达到 corePoolSize 时,新的任务会被放入到阻塞队列中等待执行。

  6. threadFactory(线程工厂): 用于创建新线程的线程工厂。如果未提供线程工厂,则默认使用 Executors.defaultThreadFactory()

  7. handler(拒绝策略): 当无法将任务提交到线程池中执行时,用于处理被拒绝的任务的策略。

    拒绝策略

    • AbortPolicy(默认): 抛出一个 RejectedExecutionException 异常来拒绝新任务的提交。

    • CallerRunsPolicy: 在调用者的线程中执行任务。如果执行器已关闭,则丢弃任务。

    • DiscardPolicy: 默默地丢弃被拒绝的任务,不做任何处理。

    • DiscardOldestPolicy: 丢弃阻塞队列中等待时间最长的任务,然后重新尝试执行新任务。

3.介绍FUllGC,minorGC,majorGC

  1. Minor GC(新生代垃圾收集): Minor GC 主要针对新生代(Young Generation)进行垃圾回收。在新生代中,对象的生命周期比较短暂,因此垃圾收集频率相对较高。Minor GC 的主要目标是清理新生代中的无用对象,并将存活的对象移动到老年代(Old Generation)或者幸存区(Survivor Space)。

  2. Major GC(老年代垃圾收集): Major GC 主要针对老年代进行垃圾回收。在老年代中,对象的生命周期较长,因此垃圾收集的频率相对较低。Major GC 的主要目标是清理老年代中的无用对象,以避免老年代空间的耗尽。

  3. Full GC(完全垃圾收集): Full GC 是对整个堆内存进行垃圾回收,包括新生代和老年代。Full GC 会清理整个堆内存中的无用对象,并且会尝试进行内存压缩(Compact),以便释放不连续的内存空间。Full GC 的触发条件通常包括老年代空间不足、永久代空间不足(在 JDK 8 及之前版本存在永久代,在 JDK 8 之后被元数据区(Metaspace)替代)、频繁的 Minor GC 等情况。

4.Java垃圾回收算法

  1. 标记-清除算法(Mark and Sweep): 这是最基本的垃圾回收算法之一。它通过标记所有活动对象,然后清除未标记的对象来进行垃圾回收。但是,标记-清除算法存在碎片化的问题,即回收后的内存空间可能会变得不连续,导致后续的内存分配效率降低。

  2. 复制算法(Copying): 复制算法将堆内存划分为两个区域,通常是 Eden 区和两个 Survivor 区。在垃圾回收时,将存活的对象从一个区域复制到另一个区域,然后清理掉原来的区域。复制算法解决了标记-清除算法中的碎片化问题,但是它需要额外的内存空间来进行对象复制。

  3. 标记-整理算法(Mark and Compact): 标记-整理算法首先标记所有活动对象,然后将它们向堆内存的一端移动,然后清理掉另一端的内存。这样可以解决标记-清除算法中的碎片化问题,但是需要额外的时间来整理内存。

  4. 分代算法(Generational): 分代算法基于一个观察:大部分对象的生命周期很短暂,只有少部分对象会存活很长时间。因此,堆内存被划分为多个代(Generation),通常是新生代(Young Generation)、老年代(Old Generation)和永久代(Perm Generation,在 JDK 8 之前的版本中存在)。不同代采用不同的垃圾回收算法,如新生代通常采用复制算法,老年代通常采用标记-清除或标记-整理算法。这样可以根据对象的生命周期选择合适的回收算法,提高回收效率。

  5. 增量式算法(Incremental): 增量式算法将垃圾回收过程分解为多个阶段,在每个阶段中执行部分垃圾回收操作,然后让应用程序执行一段时间,然后再进行下一个阶段的垃圾回收。增量式算法可以减少垃圾回收造成的停顿时间,提高系统的响应性能。

5.QPS,TPS

  1. QPS(Queries Per Second): QPS 是指每秒钟处理的查询请求数量。通常用于衡量数据库、缓存、Web 服务器等系统的性能。例如,一个数据库每秒钟能够处理的查询请求数量就是它的 QPS。

  2. TPS(Transactions Per Second): TPS 是指每秒钟完成的事务数量。事务可以是系统中的任何一种操作,例如支付、订单处理、网络请求等。TPS 通常用于衡量事务处理系统的性能。例如,在一个电子商务网站中,每秒钟完成的订单数量就是该网站的 TPS。

6.加密方式->加密的介绍

  1. 对称加密(Symmetric Encryption): 在对称加密中,加密和解密使用相同的密钥。这意味着发送方和接收方必须在通信开始前协商好密钥,并且保证密钥的安全性。常见的对称加密算法包括 DES、3DES、AES 等。对称加密具有加密速度快、效率高的优点,但密钥管理和分发可能存在安全隐患。

  2. 非对称加密(Asymmetric Encryption): 非对称加密使用一对密钥,即公钥和私钥。公钥用于加密数据,私钥用于解密数据。因为公钥可以公开,所以发送方无需与接收方事先共享密钥。常见的非对称加密算法包括 RSA、DSA、ECC 等。非对称加密通常比对称加密慢,但在密钥管理和分发方面更为灵活和安全。

  3. 哈希函数(Hash Function): 哈希函数将任意长度的输入转换成固定长度的输出,称为哈希值。哈希函数是单向的,即无法从哈希值反推出原始输入。常见的哈希函数包括 MD5、SHA-1、SHA-256 等。哈希函数常用于验证数据的完整性、密码存储、数字签名等领域。

  4. 混合加密(Hybrid Encryption): 混合加密结合了对称加密和非对称加密的优点。通常使用非对称加密算法加密对称加密的密钥,然后使用对称加密算法加密实际数据。这样可以保证通信的安全性,同时提高效率。

  5. 公钥基础设施(Public Key Infrastructure,PKI): PKI 是一种基于公钥加密的体系结构,用于管理和分发公钥、数字证书以及验证数字签名。PKI 提供了一个安全的框架,用于建立信任和保护通信的安全性。

7.实时大屏的实现逻辑

  1. 数据采集: 实时大屏需要从各种数据源获取实时数据。数据源可以是传感器、数据库、日志文件、API 接口等。数据采集的方式包括轮询、订阅/发布、推送等,取决于数据源的特点和数据的实时性要求。

  2. 数据处理: 采集到的数据可能需要进行清洗、过滤、聚合等处理,以便于后续的展示和分析。数据处理通常会使用流式处理技术,确保数据能够及时、准确地被处理和分析。

  3. 数据存储: 处理后的数据可能需要被持久化存储,以便于后续的查询和分析。数据存储可以选择合适的数据库或数据仓库,如关系型数据库、NoSQL 数据库、数据湖等。

  4. 数据可视化: 实时大屏的核心是数据可视化,即将处理后的数据以图表、地图、仪表盘等形式直观展示出来。常见的可视化工具包括 ECharts、D3.js、Highcharts 等,它们提供了丰富的图表类型和交互功能,能够满足不同场景的需求。

  5. 实时更新: 实时大屏需要保持数据的实时更新,以反映最新的状态和变化。这通常需要使用 WebSocket 或长轮询等技术,确保数据能够实时推送到前端页面,并及时更新展示内容。

  6. 用户交互: 为了提供更好的用户体验,实时大屏通常会支持用户交互功能,如筛选数据、切换视图、调整参数等。这可以通过前端页面的交互组件实现,如下拉框、滑动条、按钮等。

  7. 安全和权限控制: 对于涉及敏感数据的实时大屏,安全和权限控制是必不可少的。需要确保数据传输的加密安全,同时对用户的访问权限进行认证和授权,以保护数据的安全性和隐私。

8.介绍websocket的客户端和服务的连接过程

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,允许在客户端和服务器之间进行实时的双向数据传输。下面是 WebSocket 客户端和服务器之间连接的简要过程:

  1. 建立握手(Handshake):

    • 客户端向服务器发起 WebSocket 连接请求。这通常是通过发送 HTTP 请求的方式进行,其中包含一些特殊的头部字段,如 Upgrade: websocketConnection: Upgrade

    • 服务器收到请求后,会进行协议升级,确认将使用 WebSocket 协议进行通信。服务器会返回 HTTP 101 状态码(Switching Protocols),表示协议切换成功。

  2. 建立连接(Establish Connection):

    • 一旦握手成功,客户端和服务器之间的 TCP 连接就建立起来了。这个连接是长期保持的,允许双向实时通信。
  3. 发送数据(Send Data):

    • 客户端和服务器都可以通过已建立的连接发送数据。数据以消息的形式进行传输,可以是文本、二进制等格式。

    • 客户端和服务器可以通过发送数据来实现双向通信,无论是单个消息还是多个消息。

  4. 关闭连接(Close Connection):

    • 当某一方希望关闭连接时,可以发送关闭帧(Close Frame)来通知对方。关闭帧包含一个状态码和可选的关闭原因。

    • 接收到关闭帧后,另一方也会发送一个关闭帧作为确认。一旦双方都发送了关闭帧,连接就会被正常关闭。

需要注意的是,WebSocket 在握手阶段使用 HTTP 协议来完成,但在连接建立后会切换到 WebSocket 协议进行通信。这使得 WebSocket 能够绕过一些防火墙和代理服务器的限制,提供更加稳定和高效的实时通信服务。

9.什么是 Java 中的面向对象编程(OOP)?

在 Java 中,面向对象编程(OOP)是一种程序设计范式,它将程序中的数据和操作封装为对象,并通过对象之间的交互来实现程序的逻辑。面向对象编程主要包括以下几个核心概念:

  1. 封装(Encapsulation):指将数据(属性)和操作(方法)封装在对象内部,对外部隐藏对象的内部实现细节,只提供公共的访问接口。这样可以增强安全性和简化编程。

  2. 继承(Inheritance):允许一个类(子类)基于另一个类(父类)的定义来定义自己的新类。子类可以继承父类的属性和方法,从而实现代码重用和层次化组织。

  3. 多态(Polymorphism):允许不同的对象对同一消息做出响应,即同样的方法调用可能会产生不同的行为。多态性使得程序可以在不同的对象类型上执行相同的操作,并根据对象实际类型来决定具体的行

10.ioc和aop的理解

  1. AOP(面向切面编程)

    • AOP 是一种编程范式,它的核心思想是将程序的业务逻辑与横切关注点(如日志记录、事务管理、安全控制等)分离开来,通过将这些横切关注点模块化,可以增强代码的可重用性和可维护性。

    • AOP 的实现方式通常是通过定义切面(Aspect),在切面中指定横切关注点,并在程序执行过程中将切面织入到业务逻辑代码中,从而实现横切关注点的功能。

    • AOP 的优势在于可以使程序的各个模块更好地解耦,避免代码的重复编写,提高代码的可读性和可维护性。

  2. IOC(控制反转)

    • IOC 是一种设计原则,其核心思想是将程序的控制权从应用程序代码中反转到容器或框架中,由容器负责控制对象的创建和组装。

    • 在传统的面向对象编程中,对象的创建和依赖关系通常由程序员显式地管理,而在 IOC 容器中,对象的创建和依赖关系由容器自动管理。

    • IOC 的实现方式通常是通过依赖注入(Dependency Injection),容器负责将对象的依赖关系注入到对象中,从而达到解耦的效果。

    • IOC 可以降低系统的耦合度,提高代码的灵活性和可测试性,使得程序更易于扩展和维护。

**11.**Java中常见的集合有那些也叫juc?

Collection接口派生了list,set接口又派生了arrayList LinkedList,TreeSet,HashSet 类

Map接口派生了hashtable,hashMap,currentHashmap

list和set的区别

list是一个有序的,可重复的,元素可以有空值的集合

set 无序的、不可重复的、可以插入一个null元素的集合

hashset和treeset区别

  1. 内部实现:

    • HashSet: 使用哈希表实现,它通过哈希函数将元素映射到哈希表中的位置来存储元素。HashSet 允许存储 null 元素,并且是无序的,即元素没有特定的顺序。

    • TreeSet: 使用红黑树(一种自平衡的二叉查找树)实现,它会根据元素的自然顺序或者根据提供的 Comparator 进行排序。TreeSet 不允许存储 null 元素,并且是有序的,即元素按照排序规则排列。

  2. 性能:

    • HashSet: 在平均情况下,HashSet 的插入、删除和查找操作的时间复杂度为 O(1),但在最坏情况下可能会达到 O(n)。

    • TreeSet: 插入、删除和查找操作的时间复杂度为 O(log n),因为它是基于红黑树实现的,具有较好的平衡性能。

  3. 元素顺序:

    • HashSet: 元素存储顺序不固定,没有特定的顺序。

    • TreeSet: 元素按照排序规则有序排列。

  4. 对比和排序:

    • HashSet: 适用于快速插入、删除和查找元素,但不保证元素的顺序。

    • TreeSet: 适用于需要有序集合以及需要实现自然排序或者自定义排序的场景。

  5. 允许元素类型:

    • HashSet: 允许存储任何类型的元素,包括 null。

    • TreeSet: 允许存储任何非 null 元素,但元素必须实现 Comparable 接口或者在创建 TreeSet 时提供 Comparator。

12、ArrayList和LinkedList的区别**

ArrayList是 基于数组实现的 查询快 增删慢

LinkedList是 基于双向链表实现的: 增删快 查询慢

13、HashMap的底层原理,扩容机制?

jdk1.7之前是数组加链表1.7以后是数组加链表加红黑树

hashmap为什么长度是2的幂次方

提高hashmap存取效率,减少hash碰撞

扩容机制:

移位运算扩容

当加载因子超过一定阈值时(默认为0.75),HashMap会自动进行扩容。

当链表长度大于等于8,且 HashMap 的容量小于64时,会进行一次扩容

为什么加载因子是0.75

因为设计之初就是要么拿空间换时间,要么拿时间换空间,得到的结果就是0.75是最完美的。

什么时候会转为红黑树:

当链表长度过长时,会将链表转换为红黑树,以提高查询、插入等操作的效率。具体来说,当链表的长度超过一定阈值(默认为8)会触发链表转换为红黑树的操作。

什么时候会转回去 :

当红黑树的节点数减少到一定程度(默认为6),且 HashMap 的容量小于64时,会将红黑树转换回链表。这是因为在节点数量较少的情况下,红黑树的维护成本可能会超过链表,因此回退到链表结构更为合适。

为什么要转为红黑树:

因为红黑树在一些操作上具有更好的性能表现,例如在平均情况下,红黑树的查询、插入和删除操作的时间复杂度都是 O(log n),而链表的时间复杂度则是 O(n)。当链表长度较长时,红黑树的性能优势就会体现出来。

什么叫hash碰撞:

hash碰撞指的是,两个不同的值(比如张三、李四的学号)经过hash计算后,得到的hash值相同,后来的李四要放到原来的张三的位置,但是数组的位置已经被张三占了,导致冲突。

hash碰撞的解决方式是什么:

hash碰撞的解决方式是开放寻址法。 开放寻址法指的是,当前数组位置1被占用了,就放到下一个位置2上去,如果2也被占用了,就继续往下找,直到找到空位置。

1. 什么是移位运算符?

在 Java 中,移位运算符用于对二进制数进行位移操作。它们可以将一个数的所有位向左或向右移动指定的位数。

Java 提供了三种移位运算符:

  • 左移运算符(<<):将一个数的所有位向左移动指定的位数,并在低位补 0。

  • 右移运算符(>>):将一个数的所有位向右移动指定的位数,并根据原来最高位的值,在高位补上相同的值。

  • 无符号右移运算符(>>>):将一个数的所有位向右移动指定的位数,并在高位补 0。

2. 为什么需要移位运算符?

移位运算符主要用于处理二进制数据和优化某些计算过程。它们可以快速地进行乘法、除法和取模等运算,同时也可以用于位掩码和位标志的设置与清除。

3. 移位运算符的实现原理

移位运算符的实现原理是基于二进制数的位操作。具体来说,左移运算符(<<)将一个数的所有位向左移动指定的位数,右移运算符(>>)将一个数的所有位向右移动指定的位数,并根据原来最高位的值,在高位补上相同的值,无符号右移运算符(>>>)将一个数的所有位向右移动指定的位数,并在高位补 0。

14.HashMap,HashTable,CurrentHashMap的区别

线程安全:

hashmap是线程不安全的类,hashtable是线程安全的类(内部的方法都使用了synchronized同步关键字),currentHashMap是线程安全的类(它的底层是(Segment)分段锁可以实现不同线程可以同时读取不同段的数据,提高了并发性能。性能)

键是否为空:

hashmap允许键和值都为空 ,hashtable键和值都不允许为空,在 ConcurrentHashMap 中,键和值都不允许为空(null)

扩容机制:

HashMap 和 ConcurrentHashMap 的扩容机制类似,都是在元素数量达到一定阈值时进行扩容。

HashTable 在扩容时会重新计算哈希值,重新分配位置,并且容量必须为 2 的幂次方。

15、* *线程的实现方式?**

继承Thread类

实现Runnable,Callable接口

通过线程池

Runnable,Callable的区别

Runnable 无返回值

Callable 有返回值

16.线程状态有那些,通过那些方法进行切换

新建 就绪 运行 阻塞 等待 死亡

start() 方法:启动线程,使线程从新建状态转变为就绪状态。

sleep(long millis) 方法:使线程进入超时等待状态

wait() 方法:使线程进入等待状态,线程将等待其他线程调用

join() 方法:使调用线程进入等待状态,等待被调用线程执行完毕后才能继续执行。

notify() 和 notifyAll() 方法:用于唤醒处于等待状态的线程,使其进入就绪状态。

stop() 方法(已废弃):强制终止线程,使线程从任何状态直接转变为终止状态,不推荐使用。

17、* *Java中常见的设计模式,至少理解5个?**

*单例模式*(Singleton Pattern):确保类只有一个实例,并提供一个全局访问点。

*工厂模式*(Factory Pattern):定义一个接口用于创建对象,但允许子类决定实例化哪个类。这样可以将对象的创建与使用者解耦,提高了代码的灵活性和可维护性。

*观察者模式*(Observer Pattern):定义了对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这在实现事件监听器、发布-订阅系统等场景中非常有用。

*代理模式*(Proxy Pattern):为其他对象提供一种代理以控制对这个对象的访问。代理模式通常用于实现延迟加载、权限控制等功能。Aop使用的是代理模式

*建造者模式*:允许逐渐创建一个复杂的对象 ,并在创建的过程中可以灵活的添加或修改其内的属性 build参数的时候使用。

策略模式: 策略模式是一种行为设计模式,它允许在运行时选择算法的行为。它定义了一系列算法,将每个算法封装在独立的类中,并使它们可以相互替换,从而使得算法可以独立于其使用者而变化。策略模式通过将算法的实现与其使用者分离,提高了代码的灵活性和可维护性。

18、* *Spring框架的ioc?DI注入的方式有那些?**

Ioc控制反转

DI依赖注入

在 Spring 中实现依赖注入的常见方式有以下 3 种:

· 属性注入(Field Injection);也就是@Autowired

· Setter 注入(Setter Injection);

· 构造方法注入(Constructor Injection)。

19、* *Spring的事务?事务的传播行为有那些?**

1.编程式事务管理

编程式事务管理需要在Java代码中显示地控制事务,即显式地开始、提交或回滚事务。但是,这种方式较复杂且可读性不好,因此一般不推荐使用。

2.声明式事务管理

声明式事务管理是一种更高级别的抽象,它可以通过配置文件轻松地管理事务。在声明式事务管理中,我们将特定方法定义为事务,并将这些方法配置到Spring配置文件中。当这些方法被调用时,Spring会在事务开始前和结束时自动管理它们。

我一般用的都是REQUIRED因为REQUIRED是Spring事务的默认方式 他的意思就是,如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务,偶尔也会用到:REQUIRES_NEW:每次都会创建一个新的事务,并且挂起当前的事务(如果存在)。

其余的倒是不怎么用

REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是最常用的传播行为,也是Spring的默认传播行为。

SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式执行。

MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

REQUIRES_NEW:每次都会创建一个新的事务,并且挂起当前的事务(如果存在)。

NOT_SUPPORTED:以非事务的方式执行操作,如果当前存在事务,则将事务挂起。

NEVER:以非事务的方式执行操作,如果当前存在事务,则抛出异常。

NESTED:如果当前存在事务,则创建一个嵌套事务,并在嵌套事务内执行;如果当前没有事务,则行为类似于REQUIRED。

UNKNOWN:由容器自动选择适当的事务传播行为,通常用于与其他事务处理框架进行集成。

20、* *Redis 支持的数据类型有哪些?有哪些应用场景?什么是缓存穿透?怎么解决?** *.*

Redis支持的数据类型包括:

字符串(String):存储字符串、整数或浮点数。

列表(List):按插入顺序存储多个元素的列表。

集合(Set):包含多个不重复元素的无序集合。

有序集合(Sorted Set):类似于集合,但每个元素都有一个相关联的分数,用于排序。

哈希表(Hash):包含字段和与之相关联的值的无序散列表。

字符串常用于缓存数据、计数器、分布式锁等。

列表可用于消息队列、最新动态等。

集合和有序集合可用于标签系统、排行榜等。

哈希表可用于存储对象的字段和值。

缓存穿透是指恶意或异常查询导致缓存无法命中,导致请求直接落到数据库上,增加数据库负载的情况。

缓存击穿是指某个热点数据突然失效或过期,导致大量请求同时访问数据库,引起数据库压力激增的情况。

缓存雪崩是指大规模缓存失效,导致请求直接落到数据库上,引起数据库压力激增,甚至导致数据库崩溃的情况。

解决缓存穿透、击穿和雪崩的方法包括:

*缓存穿透*

使用布隆过滤器过滤掉不存在的数据。

缓存空值,设置短暂的过期时间。

*缓存击穿*

使用互斥锁或分布式锁来保护热点数据,防止同时大量请求访问数据库。

提前预加载热点数据到缓存中,或设置热点数据永不过期。

*缓存雪崩*

设置不同的过期时间,避免大量缓存同时失效。

使用多级缓存架构,如热点数据采用内存缓存,冷数据采用持久化缓存,以减轻缓存失效的影响范围。

数据预热,提前加载热点数据到缓存中。

使用限流、降级等手段控制流量,避免突发流量冲击数据库。

21、* *解释一下什么是 aop?有那些使用场景?**

Aop就是面向切面编程 通过@Aspect定义一个切面 然后通过定义切点(Pointcut )来进行决定切入哪个方法 通过通知来加一些业务代码 通知包括 (前置通知,环绕通知,后置通知,异常通知,最终通知)

使用场景包括但不限于:

日志记录:在方法调用前后记录方法的输入参数、返回值等信息,用于调试和性能监控。

事务管理:在方法调用前开启事务,在方法执行后提交或回滚事务,确保数据一致性和完整性。

安全性:对方法进行权限验证,如检查用户是否有权限执行特定操作。

异常处理:在方法执行过程中捕获异常并进行处理,如记录异常信息或进行异常转换。

性能监控:统计方法的执行时间、调用次数等性能指标,用于性能优化和系统监控。

缓存管理:在方法执行前检查缓存是否命中,若命中则直接返回缓存结果,否则执行方法并将结果缓存起来。

22、* *synchronized 和 volatile 的区别是什么?**

Synchronized 修饰方法,代码块,volatile修饰变量

Synchronized 同一时刻,只能有一个线程持有锁,保证原子性

Volaite 不能保证原子性,但一旦修改,其它线程立即可见

23、* *如何决定使用 HashMap 还是 TreeMap?**

适用于在Map中插入、删除和定位元素。 如果你需要得到一个有序的结果时就应该使用TreeMap(因为HashMap中元素的排列顺序是不固定的)。 除此之外,由于HashMap有更好的性能,所以大多不需要排序的时候我们会使用HashMap

24、* *防止数据重复提交的方法?**

在后端我经常用的方式就是使用redis里面的一个分布式锁,

在前端我用的方法就是点击按钮以后直接禁用这个按钮

25、* *ThreadLocal 是什么?有哪些使用场景?**

ThreadLocal 是 Java 中的一个线程的变量(在每次前端请求访问后端时会创建一个线程)

ThreadLocal 主要由以下几个方法组成:

void set(T value): 设置当前线程的变量副本的值。

T get(): 获取当前线程的变量副本的值。

void remove(): 移除当前线程的变量副本。

protected T initialValue(): 提供默认值的方法,在首次调用 get() 时使用。

使用场景:

*存放用户信息:*

因为前端每次请求都会创建一个线程的原因可以在拦截时把用户信息存入到threadLocal变量里面为以后的使用提供便捷

*数据库连接池:*

数据库连接池使用的也是threadlocal 因为其可以确保不同时间多线程可以拿到不同的数据库连接

26、 *== 和 equals 的区别是什么?*

在基本数据类型中

== 操作符比较的是对象的内容是否相同。

在引用数据类型中

== 操作符比较的是对象的引用地址是否相同。

equals() 方法只能比较引用数据类型,比较主要是根据equals方法实现,如果equals没有被重写内部方法就是== ,如果被重写了就按重写的方法走

27、* *String 类的常用方法都有那些?**

String常用的方法有

字符串截取substring ,

获取字符串下标indexof,

获取字符串长度Leanth,

比较字符串内容是否相等 equals

字符串分割 split

28、* *Mybatis** *如何避免 SQL 注入?*

Mybatis里面有两种注入方式 一种是#{}符号 一种是${}符号 #符号是经过预编译的所以是安全的 $符号是没有经过预编译的所以不是安全的,存在sql注入

29、* *项目中** *如何实现跨域?*

可以通过使用注解的方式,配置文件,配置网关 我在项目中一般都是用的网关

30. *@Autowired和@Resource的区别?*

Autowired 是 spring框架带的注解

Resource 是 javaee自带的注解

Autowired 根据type注入对象 如果存在多个一样的对象 可以使用qualifier注解或者primary注解 来指定注入对象

Resource有两种注入方式 一种是name另一种是type 如果name有值则使用byname的自动注入策略如果type有值则使用bytype的自动注入策略 ,如果name和type都没有值就会通过反射机制使用byname自动注入策略

31. *Springboot的核心注解是哪个?它主要由哪几个注解组成*

在 Spring Boot 中,核心注解是 @SpringBootApplication。这个注解通常用于启动类上,它整合了多个注解,包括了:

@Configuration:标识该类可以使用 IoC 容器作为 bean 定义的来源。

@EnableAutoConfiguration:启用 Spring Boot 的自动配置机制,它根据 classpath 下的 jar 包依赖为当前项目进行自动配置。

@ComponentScan:启用组件扫描,以便 Spring 能够发现并注册 Spring 管理的 bean。

32. *深克隆 浅克隆?*

浅克隆

浅克隆指的是在复制对象时,只复制对象本身及其基本数据类型属性的值,而不复制对象中引用类型属性所引用的对象

深克隆

深克隆指的是在复制对象时,不仅复制了对象本身,还复制了对象中所有的引用类型属性所引用的对象,以及这些对象所引用的对象,依次类推,直到所有相关的对象都被完全复制。

区别

深克隆与浅克隆的区别就是,浅克隆不会克隆原对象中的引用类型,仅仅拷贝了引用类型的指向。深克隆则拷贝了所有。也就是说深克隆能够做到原对象和新对象之间完全没有影响。

而深克隆的实现就是在引用类型所在的类实现Cloneable接口,并使用public访问修饰符重写clone方法

33. *Spring中事务失效的场景有哪些*

因为事务就是利用aop动态代理做的

所以方法被final修饰,final修饰方法无法重写 static修饰的方法也不行,

Try catch 捕获异常也不可以,

方法不是public修饰的也是不行的,

(面试时不说)事物的失效场景:

一个不开启事务的方法去调用开启事务的方法,在开启事物的方法中,其调用了两个保存方法,在过程中存在了异常,事物会失效

解决方案:两个方法都开启事务

34. *MySQL中,如何定位慢查询* *,**** *SQL语句执行很慢, 如何分析呢****?****

*如何定位慢查询*

我们当时部署一个 运维监控系统Druid ,可以实时监控系统的运行情况,可以查看出每个接口的运行时间,从这里我们就可以看到那个接口的运行速度比较慢,这样我们就可以快速定位到是哪个sql出了问题

如果项目中没有运维监控系统,我们可以在 MySQL 的系统配置文件中开启慢查询日志功能。通过设置 SQL 执行时间的阈值,当某个 SQL 执行时间超过设定的阈值(比如2秒)时,我们可以通过产看日志的方式找到这条慢sql

*如何分析呢*

如果一条sql执行很慢的话,我们可以通过explain的方式去查看这条sql上面是否存在索引,如果这条sql上面没有存在索引我们就要去吧索引给加上,如果存在了索引,就要查看一下索引是否有失效的情况

第二个,可以通过type字段查看sql是否有进一步的优化空间,是否存在全索引扫描或全盘扫描

35. *mysql什么是索引,以及索引的底层数据结构*

在MySQL中,索引是一种用于快速查找数据的数据结构,它可以加速数据检索操作的速度。索引类似于书籍的目录,通过按照某种顺序对数据进行排序并建立索引,可以快速定位到所需的数据行,而不需要扫描整个表格。

索引数据结构:

Hash

b-tree

*36.**B树和B+树的区别是什么呢?***

B树的节点中没有重复元素b+树有

b树的中间节点会存储数据指针信息b+树只有叶子结点才会存储

b+树的每一个叶子结点有一个指针执向下一个节点把所有的叶子结点串在了一起

*37.* *sql的优化的经验*****,结合项目说sql优化;****

limit 深分页问题的本质原因就是:偏移量(offset)越大,mysql就会扫描越多的行,然后再抛弃掉。这样就导致查询性能的下降

我当时在项目中遇到的就是mysql的深分页优化,当时就是百万数据查询很慢,我当时的解决方案就是标签记录法

就是标记一下上次查询到哪一条了,下次再来查的时候,从该条开始往下扫描。就好像看书一样,上次看到哪里了,你就折叠一下或者夹个书签,下次来看的时候,直接就翻到啦

假设上一次记录到100000,则SQL可以修改为:select id,name,balance FROM account where id > 100000 order by id limit 10;

38.java自带的线程池有哪几种

  1. FixedThreadPool(固定大小线程池)

    • FixedThreadPool 是一种固定大小的线程池,其中的线程数量是固定的,当有新任务提交时,如果线程池中有空闲线程,则立即执行任务;如果没有空闲线程,则任务会被放入任务队列中等待执行。

    • 适用于需要限制并发线程数量的场景,如控制资源消耗等。

  2. CachedThreadPool(缓存线程池)

    • CachedThreadPool 是一种可缓存的线程池,它的线程数量不固定,会根据需要动态创建新的线程。

    • 当有新任务提交时,如果有空闲线程,则直接使用空闲线程执行任务;如果没有空闲线程,则会创建新的线程。如果线程在60秒内没有被使用,则会被终止并从线程池中移除。

    • 适用于执行大量短期异步任务的场景,如网络爬虫等。

  3. SingleThreadExecutor(单线程线程池)

    • SingleThreadExecutor 是一个单线程的线程池,它只有一个工作线程,确保所有任务按顺序执行。

    • 当有多个任务提交时,这些任务会被放入一个任务队列中,然后由单个工作线程依次执行。

    • 适用于需要顺序执行任务的场景,如事件处理等。

  4. ScheduledThreadPool(定时线程池)

    • ScheduledThreadPool 是一种定时执行任务的线程池,它可以延迟执行任务,也可以周期性执行任务。

    • 可以通过 schedule() 方法延迟执行任务,或者通过 scheduleAtFixedRate()scheduleWithFixedDelay() 方法周期性执行任务。

    • 适用于需要定时执行任务的场景,如定时任务调度等。

39.为什么使用线程池 线程池每个参数的意义 执行的过程

使用线程池的主要目的是提高线程的利用率、减少线程创建和销毁的开销、控制并发线程数量,从而提高系统的性能和稳定性。以下是使用线程池的几个主要原因:

  1. 减少资源消耗: 创建和销毁线程是有开销的,包括线程对象的创建、上下文切换等。使用线程池可以重用已经创建的线程,减少了频繁创建和销毁线程的开销,从而降低了系统的资源消耗。

  2. 提高响应速度: 当任务到达时,线程池中已经存在的线程可以立即执行任务,而不需要等待新线程的创建,从而提高了任务的响应速度。

  3. 控制并发度: 通过设置线程池的大小,可以控制并发执行的线程数量,避免因线程过多导致系统资源耗尽或性能下降的情况。

  4. 管理线程: 线程池提供了一种统一的管理机制,可以对线程进行统一管理和监控,包括线程的状态、执行情况等。

线程池的参数及其意义如下:

  1. corePoolSize(核心线程数): 线程池中保持活动状态的线程数量,即使它们处于空闲状态。当有任务提交时,线程池会优先使用核心线程来执行任务,而不是创建新的线程。

  2. maximumPoolSize(最大线程数): 线程池中允许的最大线程数量,包括核心线程和非核心线程。当任务提交的数量超过了核心线程数,并且任务队列已满时,线程池会创建新的线程,但不会超过最大线程数。

  3. keepAliveTime(线程空闲时间): 当线程池中的线程数量超过核心线程数时,空闲线程的最大存活时间。当线程空闲时间超过 keepAliveTime 时,多余的线程会被销毁,直到线程池中的线程数等于核心线程数。

  4. unit(时间单位): keepAliveTime 的时间单位,通常为 TimeUnit 类型,可以是秒、毫秒等。

  5. workQueue(任务队列): 用于存放等待执行的任务的阻塞队列,可以是有界队列(如 ArrayBlockingQueue)或无界队列(如 LinkedBlockingQueue)。

  6. threadFactory(线程工厂): 用于创建新线程的工厂类,可以自定义线程的名称、优先级等属性。

  7. rejectedExecutionHandler(拒绝策略): 当任务提交到线程池被拒绝时的处理策略,例如抛出异常、丢弃任务、调用者执行任务等。

线程池的执行过程如下:

  1. 当有任务提交到线程池时,线程池首先判断当前活动线程数是否小于核心线程数,如果是,则创建新的核心线程来执行任务。

  2. 如果活动线程数已经达到了核心线程数,并且任务队列未满,则将任务加入到任务队列中等待执行。

  3. 如果任务队列已满,但活动线程数未达到最大线程数,则创建新的非核心线程来执行任务。

  4. 如果活动线程数已经达到了最大线程数,并且任务队列已满,则根据指定的拒绝策略来处理任务提交失败的情况。

  5. 当任务队列中有任务执行完成时,线程池会从队列中取出任务并交给空闲线程执行,或者在空闲线程达到 keepAliveTime 后销毁空闲线程,直到线程池中的线程数量等于核心线程数。

通过合理地设置线程池的参数,可以有效地控制系统的并发度,提高系统的性能和稳定性。

mvc实现流程

SpringMVC执行流程: 1.用户发送请求至前端控制器DispatcherServlet 2.DispatcherServlet收到请求调用处理器映射器HandlerMapping。 3.处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。 4.DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作 5.执行处理器Handler(Controller,也叫页面控制器)。 6.Handler执行完成返回ModelAndView 7.HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet 8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器 9.ViewReslover解析后返回具体View 10.DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。 11.DispatcherServlet响应用户。

40事务的特性是什么,以及并发事务有哪些问题

acid

原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。

一致性:或可串性。事务的执行使得数据库从一种正确状态转换成另一种正确状态。

隔离性:在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务。

持久性:事务正确提交后,其结果将永久保存在数据库中,即使在事务提交后有了其他故障,事务的处理结果也会得到保存。

41.Redis分布式锁如何实现,控制Redis实现分布式锁有效时长呢(redisson看门狗机制)

这个实现简单地通过 redisTemplate 模版里面有一个setIfAbsent()方法 这个方法的意思就是尝试在Redis中设置一个键值对,如果成功返回OK,则表示获得了锁。如果由于某种原因(如锁已存在)设置失败,则返回null。在锁超时后,由于设置了过期时间,锁会自动释放。

关于控制Redis实现分布式锁的有效时长,可以在设置锁的过期时间和时间单位。通过设置合适的过期时间,可以确保锁不会永远存在,从而避免死锁等问题。

对于 Redisson 的看门狗机制,它会在锁即将过期时(过期时间的一半)自动续期。Redisson会在后台启动一个定时任务,定期检查锁是否即将过期,如果即将过期,则尝试更新锁的过期时间,从而避免锁被意外释放。这个机制可以保证在锁还在使用的情况下,不会因为过期而被自动释放。

42.redis做为缓存,数据的持久化是怎么做的? (区别是什么)

Redis作为缓存的数据持久化通常有两种主要的方式:RDB(Redis DataBase)和AOF(Append Only File)。

  1. RDB(Redis DataBase)持久化

    • RDB 是 Redis 默认的持久化方式。它通过在指定的时间间隔内将内存中的数据以快照的形式写入到磁盘上的一个文件中。这个文件是一个二进制文件,包含了 Redis 在某个时间点上的数据集。

    • RDB 持久化的优点是它对数据的备份非常高效,因为它是在指定时间间隔内进行的,可以将整个数据集写入磁盘,恢复数据时也比较快速。同时,RDB 文件是一个紧凑的二进制文件,占用的空间相对较小。

    • 不过,RDB 的缺点是如果发生系统崩溃或停机时,可能会丢失最后一次持久化后的数据。

  2. AOF(Append Only File)持久化

    • AOF 是将 Redis 服务器接收到的每一条写操作都追加到文件的末尾,以日志的形式记录所有写操作。当 Redis 服务器启动时,它会重新执行这些写操作,从而恢复数据集的原始状态。

    • AOF 持久化的优点是它提供了更可靠的数据保护,因为它记录了每一次写操作,可以保证最小化的数据丢失。此外,AOF 文件是一个文本文件,可以轻松地进行人工查看和修复。

    • AOF 持久化的缺点是相对于 RDB 持久化,AOF 文件通常会更大一些,而且在恢复数据时可能会比较耗时。

spring跟springbuffer和StringBuilder 的区别

因为spring是被final修饰的最终类所以一经赋值不可改变,但是springBuffer和StringBuilder 是可以改变的,但是从线程安全性上来看,springBuffer的其内部大部分方法都被synchronized 所修饰所以是线程安全的,而StringBuilder没有这个修饰所以是线程不安全的了,在单线程的情况的因为StringBuilder 没有加锁所以执行速度更快而springBuffer每次都需要判断加锁所以效率相对于springBuilder低一些

相关推荐
qmx_0712 分钟前
HTB-Jerry(tomcat war文件、msfvenom)
java·web安全·网络安全·tomcat
为风而战21 分钟前
IIS+Ngnix+Tomcat 部署网站 用IIS实现反向代理
java·tomcat
编程零零七1 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
技术无疆2 小时前
快速开发与维护:探索 AndroidAnnotations
android·java·android studio·android-studio·androidx·代码注入
2401_858286112 小时前
52.【C语言】 字符函数和字符串函数(strcat函数)
c语言·开发语言
铁松溜达py2 小时前
编译器/工具链环境:GCC vs LLVM/Clang,MSVCRT vs UCRT
开发语言·网络
everyStudy2 小时前
JavaScript如何判断输入的是空格
开发语言·javascript·ecmascript
C-SDN花园GGbond4 小时前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法
迷迭所归处5 小时前
C++ —— 关于vector
开发语言·c++·算法
架构文摘JGWZ5 小时前
Java 23 的12 个新特性!!
java·开发语言·学习