Java面试题整理3


前言

牛客论坛项目总结部分常见面试题。


一、MySQL

1. 事务

  1. 事务的特性:原子性、一致性、隔离性、持久性
  2. 事务的隔离性
    (1)并发异常:第一类丢失更新、第二类丢失更新、脏读、不可重复读、幻读
    (2)隔离级别:Read UncommittedRead CommittedRepeatable ReadSerializable
  3. Spring事务管理:声明式事务 、编程式事务

2. 锁

  1. 范围
    (1)表级锁:开销小,加锁快,发生冲突的概率高,并发度低,不会出现死锁。
    (2)行级锁:开销大,加锁慢,发生冲突的概率低,并发度高,会出现死锁。
  2. 类型(InnoDB)
    (1)共享锁(S):行级,读取一行;
    (2)排他锁(X):行级,更新一行;
    (3)意向共享锁(IS):表级,准备加共享锁;
    (4)意向排他锁(IX):表级,准备加排他锁;
    (5)间隙锁(NK):行级,使用范围条件时,对范围内不存在的记录加锁。一是为了防止幻读,二是为了满足恢复和复制的需要。
  3. 加锁
    (1)增加行级锁之前,InnoDB会自动给表加意向锁;
    (2)执行DML语句时,InnoDB会自动给数据加排他锁;
    (3)执行DQL语句时,
    共享锁(S):SELECT ... FROM ... WHERE ... LOCK ... IN SHARE MODE;
    排他锁(X):SELECT ... FROM ... WHERE ... FOR UPDATE;
    间隙锁(NK):上述SQL采用范围条件时,InnoDB对不存在的记录自动增加间隙锁。
  4. 死锁
    (1)场景
    ① 事务1:UPDATE T SET ... WHERE ID = 1; UPDATE T SET ... WHERE ID = 2;
    ② 事务2:UPDATE T SET ... WHERE ID = 2; UPDATE T SET ... WHERE ID = 1;
    (2)解决方案
    ① 一般InnoDB会自动检测到,并使一个事务回滚,另一个事务继续;
    ② 设置超时等待参数 innodb_lock_wait_timeout;
    (3)避免死锁
    ① 不同的业务并发访问多个表时,应约定以相同的顺序来访问这些表;
    ② 以批量的方式处理数据时,应事先对数据进行排序,保证线程按固定的顺序来处理数据;
    ③ 在事务中,如果要更新记录,应申请足够级别的锁,即排他锁。
  5. 悲观锁(数据库)乐观锁(自定义)
    (1)乐观锁的实现:
    ① 版本号机制
    UPDATE ... SET..., VERSION=#{version+1} WHERE ... AND VERSION=${version}
    ② CAS算法(Compare and swap)
    是一种无锁的算法,该算法涉及3个操作数(内存值V、旧值A、新值B),当V=A时,采用原子方式用B的值更新V的值。该算法通常采用自旋操作,也叫自旋锁。
    缺点:
    a) ABA问题:某线程将A改为B,再改回A,则CAS会误认为A没有被修改过;
    b) 自旋操作采用循环的方式实现,若加锁时间长,则会给CPU带来巨大的开销;
    c) 只能保证一个共享变量的原子操作。

3. 索引

B+Tree(InnoDB)
(1)数据分块存储,每一块称为一页;
(2)所有的值都是按照顺序存储的,并且每一个叶子到根的距离相等;
(3)非叶子节点存储数据的节点,叶子节点存储指向数据行的指针;
(4)通过边界缩小数据的范围,从而避免了全表扫描,加快了查找速度。


二、Redis

1. 数据类型

  1. 最大存储数据量
    key:512M
    string:512M
    hash: 2 32 − 1 2^{32}-1 2321
    list: 2 32 − 1 2^{32}-1 2321
    set: 2 32 − 1 2^{32}-1 2321
    srted set
    bitmap:512M
    hyperloglog:12K

2. 过期策略

  1. Redis会把设置了过期时间的key放入一个独立的字典中,在key过期时并不会立刻删除它。Redis会通过如下两个策略来删除过期的key:
    (1)惰性删除
    客户端访问某个key时,Redis会检查该key是否过期,若过期则删除。
    (2)定期扫描
    Redis默认每执行10次过期扫描(配置hz选项),扫描策略如下:
    ① 从过期字典中随机选择20个key;
    ② 删除这20个key中已过期的key;
    ③ 如果过期的key的比例超过25%,重复步骤1。

3. 淘汰策略

  1. 当Redis占用内存超出最大限制(maxmemory)时,可采用如下策略(maxmemory-policy)让Redis淘汰一些数据,以腾出空间继续提供读写服务:
    (1)noeviction:对可能导致增大内存的命令返回错误(大多数写命令,DEL除外);
    (2)volatile-ttl:在设置了过期时间的key中,选择剩余寿命(TTL)最短的key,将其淘汰;
    (3)volatile-lru:在设置了过期时间的key中,选择最少使用的key(LRU),将其淘汰;
    (4)volatile-random:在设置了过期时间的key中,随机选择一些key,将其淘汰;
    (5)allkeys-lru:在所有的key中,选择最少使用的key(LRU),将其淘汰;
    (6)allkeys-random:在所有的key中随机选择一些key,将其淘汰。
  2. LRU算法:维护一个链表,用于顺序存储被访问过的key。在访问数据时,最新访问过的key被移动到表头,即最近访问的key在表头,最少访问的key在表尾。
  3. 近似LRU算法(Redis):给每个key维护一个时间戳,淘汰时随机采样5个key,从中淘汰掉最旧的key。如果还是超出内存限制,则继续随机采样淘汰。优点:比LRU算法节约内存,却可以取得非常近似的效果。

4. 缓存穿透

  1. 场景
    查询根本不存在的数据,使得请求直达存储层,导致其负载过大,甚至宕机。
  2. 解决方案
    (1) 缓存空对象
    存储层未命中后,仍然将空值存入缓存层。再次访问该数据时,缓存层会直接返回空值。
    (2)布隆过滤器
    将所有存在的key提前存入布隆过滤器,在访问缓存层之前,先通过过滤器拦截,若请求的是不存在的key,则直接返回空值。

5. 缓存击穿

  1. 场景
    一份热点数据,它的访问量非常大。在其缓存失效瞬间,大量请求直达存储层,导致服务崩溃
  2. 解决方案
    (1)加互斥锁
    对数据的访问加互斥锁,当一个线程访问该数据时,其他线程只能等待。这个线程访问过后,缓存中的数据被重建,届时其他线程就可以直接从缓存中取值。
    (2) 永不过期
    不设置过期时间,所以不会出现上述问题,这是“物理”上的不过期。
    为每个value设置逻辑过期时间,当发现该值逻辑过期时,使用单独的线程重建缓存。

6. 缓存雪崩

  1. 场景
    由于某些原因,缓存层不能提供服务,导致所有的请求直达存储层,造成存储层宕机。
  2. 解决方案
    (1)避免同时过期
    设置过期时间时,附加一个随机数,避免大量的key同时过期。
    (2)构建高可用的Redis缓存
    部署多个Redis实例,个别节点宕机,依然可以保持服务的整体可用。
    (3)构建多级缓存
    增加本地缓存,在存储层前面多加一级屏障,降低请求直达存储层的几率。
    (4)启用限流和降级措施
    对存储层增加限流措施,当请求超出限制时,对其提供降级服务。

7. 分布式锁

  1. 场景
    修改时,通常需要先将数据读取到内存,在内存中修改后再存回去。在分布式应用中,可能多个进程同时进行上述操作,而读取和修改非原子操作,所以会产生冲突。增加分布式锁,可以解决此类问题。
  2. 基本原理
    (1)同步锁:在多个线程都能访问到的地方,做一个标记,标识该数据的访问权限。
    (2)分布式锁:在说个进程都能访问到的地方,做一个标记,标识该数据的访问权限。
  3. 实现方式
    (1)基于数据库实现分布式锁;
    (2)基于Redis实现分布式锁;
    (3)基于Zookeeper实现分布式锁。
  4. Redis实现分布式锁的原则
    (1)安全性:独享。在任一时刻,只有一个客户端持有锁。
    (2)活性A:无死锁。即便持有锁的客户端崩溃或者网络被分裂,锁仍然可以被获取。
    (3)活性B:容错。只要大部分Redis节点都活着,客户端就可以获取和释放锁。
  5. 单Redis实例实现分布式锁
    (1)获取锁使用命令:
    SET resource_name my_random_value NX PX 30000
    NX:仅在key不存在时才执行成功。
    PX:设置锁的自动过期时间。
    (2)通过Lua脚本释放锁:
    if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end
    可以避免删除别的客户端获取成功的锁:
    A加锁 -> A阻塞 -> 因超时释放锁 -> B加锁 -> A恢复 -> 释放锁
  6. 多Redis实例实现分布式锁
    RedLock算法,该算法有现成的实现,其Java版本的库为Redisson。
    (1)获取当前Unix时间,以ms为单位。
    (2)依次尝试从N个实例,使用相同的key和随机值获取锁,并设置响应超时时间。如果服务器没有在规定的时间内响应,客户端应该尽快尝试另外一个Redis实例。
    (3)客户端使用当前时间减去开始获取锁的时间,得到获取锁使用的时间。当且仅当大多数的Redis节点都取到了锁,key的真正有效时间等于有效时间减去获取锁使用的时间。
    (4)如果取到了锁,key真正有效时间等于有效时间减去获取锁使用的时间。
    (5)如果获取锁失败,客户端应该在所有的Redis实例上进行解锁。

三、Spring

1. Spring IoC

  1. Bean作用域
作用域使用范围描述
singleton所有Spring应用在容器中只存在一个实例,默认值。
prototype所有Spring应用在容器中存在多个实例,即每次获取该Bean时,都会创建一个新实例。
requestSpring Web应用为每个请求创建一个新的实例。
sessionSpring Web应用为每个会话创建一个新的实例。
globalSessionSpring Web应用为全局的session创建一个实例,只在Protlet上下文中有效。
applicationSpring Web应用为整个Web应用创建一个新的实例。

2. Spring AOP

  1. 术语

原文链接:【Spring框架】Aop的六个常用术语+五种通知类型的解析+实例测试

(1)连接点(Joinpoint)
简述:所有可以定义切点的“地方”,或者说是所有可以去添加增强代码的“地方”。
详述:是在应用程序执行过程中能够插入切面的一个点,这个点可以是调用方法时,抛出异常时,甚至修改一个字段时,切面代码可以利用这些点插入到应用程序的正常流程中,并增加新的行为。
(2)切点(Pointcut)
需要去添加代码的“地方”。 描述了切面织入的位置。 切点的定义会匹配通知所要织入的一个或多个连接点,可以指定明确的类和方法,也可以使用正则表达式匹配符合条件的类和方法来指定这些切点。
(3)通知(Advice)
向切点处动态添加的那部分代码。 描述了切面要做的工作。
(4)切面(Aspect)
切点+通知。
(5)引入(Introduction)
向现有类添加新方法或属性。
(6)织入(Weaving)
把切面应用到目标对象并创建新的代理对象的过程。 切面在指定的连接点被织入到目标对象中,在目标对象的生命周期里有多个点可以进入织入:
① 编译期:切面在目标类编译时被织入。-> 需使用特殊的编译器。
② 类加载期:切面在目标类加载到JVM时被织入。-> 需使用特殊的类加载器。
③ 运行期:切面在应用运行的某个时期被织入,通常在织入切面时,AOP容器会为目标对象动态创建一个代理对象,Spring AOP就是以这种方式织入切面的。-> 需为目标生成代理对象。

3. Spring MVC

  1. 处理请求的过程
    Spring MVC执行流程
    (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响应用户。
  • 29
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 面试题整理是为了帮助准备面试的候选人更好地了解面试的内容和要求。对于Java2021的面试题整理,可以从各个方面进行组织和分类,以便更好地帮助面试者准备。下面是我对Java2021面试题整理的一些建议。 1.基础知识:面试题可以包括Java语言的基本语法、关键字、数据类型、流程控制语句、异常处理等方面的问题。这些问题可以帮助面试者检验自己对Java语言基础知识的掌握程度。 2.面向对象:面试题可以涉及Java面向对象的概念、封装、继承、多态以及接口、抽象类等方面的问题。这些问题可以帮助面试者了解Java面向对象编程的特点和应用。 3.集合框架:面试题可以包括关于Java集合框架的知识,如ArrayList、LinkedList、HashSet、HashMap等的特性、用法和区别。这些问题可以帮助面试者检验自己对Java集合框架的理解和应用能力。 4.多线程:面试题可以涉及Java多线程编程的基本概念、线程的创建与启动、线程同步与互斥、线程池等方面的问题。这些问题可以帮助面试者了解多线程编程的原理和实践。 5.IO流:面试题可以包括关于Java IO流的知识,如输入输出流的分类、字符流和字节流的区别、文件读写操作等方面的问题。这些问题可以帮助面试者检验自己对IO流的理解和应用。 6.异常处理:面试题可以涉及Java异常处理的机制、try-catch语句的使用、自定义异常等方面的问题。这些问题可以帮助面试者了解异常处理的原理和常见应用。 7.Java虚拟机:面试题可以包括Java虚拟机(JVM)的基本概念、内存模型、垃圾回收算法等方面的问题。这些问题可以帮助面试者了解JVM的工作原理和性能优化。 8.框架和工具:面试题可以涉及Java常用的开发框架和工具,如Spring、Hibernate、MyBatis、Maven等方面的问题。这些问题可以帮助面试者了解开发框架的应用和工具的使用。 通过对这些方面的面试题整理,可以帮助面试者全面了解Java2021面试的内容和要求,并有针对性地准备和复习相关知识。面试者应该注重理论的学习,同时结合实践经验进行练习,以便在面试时能够更好地展示自己的能力和潜力。同时,面试者还应注意自己的沟通能力、问题分析能力和解决问题的能力,这些都是面试过程中重要的评估指标。 ### 回答2: Java2021面试题整理主要集中在以下几个方面: 1. 基础知识:Java中的基本数据类型、变量和常量、运算符、控制语句等内容是面试中常见的考点。面试官会通过这些问题判断候选人对Java基础知识的熟悉程度和掌握能力。 2. 面向对象编程:Java是一门面向对象的编程语言,所以面试中对面向对象的理解和应用也是重要的考点。常见的问题包括类和对象、继承和多态、封装和抽象等。 3. 异常处理:Java中的异常处理是编程中的重要内容,面试中会涉及到异常的概念、异常的分类、如何捕获和处理异常、自定义异常等。 4. 集合框架:Java集合框架是Java开发中常用的工具,常见的面试题会涉及到ArrayList、LinkedList、HashMap等集合的特点和应用场景,以及集合的遍历和使用方法。 5. 多线程:Java是一门支持多线程的语言,所以多线程的知识也是面试中的热点考点。常见的问题包括线程的生命周期、线程同步与互斥、线程间的通信、线程池等。 6. JVM相关知识:Java虚拟机(JVM)是Java运行的基础,所以对JVM的了解也是面试中的重要考点。常见问题包括JVM的结构、内存模型、垃圾回收机制等。 此外,面试中还可能涉及到数据库、网络编程、设计模式等其他相关知识。因此,面试前需要对Java的相关知识有全面的掌握,并且要能够灵活运用这些知识进行问题的解答。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值