美团后端Java实习一面面经

news2025/1/17 1:00:58

说一下AOP?

面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的技术。可以减少程序中相同代码的编写,简化开发,使得接口更加专注于业务

相关概念

  • Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。

 

  • Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。

 

  • Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。

 

  • Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。

如何实现

1. AspectJ

AspectJ主要作用于编译时增强, 也称之为静态代理, 我们在写完一段独立的业务方法saveData()时, 可以使用aspectJ将切面逻辑织入到saveData()中. 比如日志记录.

在使用aspectJ编译代码之后, 我们的class文件中会多出一段代码, 这段代码是aspectJ在编译时增加的aop代码. AspectJ的这种做法可以被称为静态代理

Aspect在编译期, 为被代理方法织入我们在aspect中定义好的切面逻辑, 以添加字节码的方式(强行添加代码)

2. JDK动态代理

jdk动态代理使用jdk自带的反射机制来完成aop的动态代理, 使用jdk自带的动态代理有如下要求:

1.被代理类(我们的业务类)需要实现统一接口

2.代理类要实现reflect包里面的接口InvocationHandler

3.通过jdkProxy提供的静态方法newProxyInstance(xxx)动态创建代理类

代理类和被代理类使用同样的对象引用,因此我们可以神不知鬼不觉地使用我们的真实业务类, 而无需关注在它周围的切面逻辑(独立性), 

 

说一下IOC?

loC——Inversion of Control 即“控制反转”,是一种设计思想。在java开发中,loc意味着将你设计好的对象交给容器控制,而不是传统的由对象内部控制。loc通常是由DI实现的,下面我们介绍一下DI。

​ DI------Dependency Injection,即依赖注入,组件之间的依赖关系由容器在运行期决定,即由容器动态地将某个依赖关系注入到组件当中。依赖注入的目的是为了提升组件重用的频率,并为系统搭建一个灵活可扩展的平台。

核心要点:

1.对象依赖于IOC/DI容器,因为对象需要IOC/DI容器来提供对象需要的外部资源。

2.IOC/DI容器注入对象,注入的是某个需要的东西那就是注入对象所需要的资源

3.IOC/DI容器控制对象,主要是控制对象实例的创建

案例:常规情况下的应用程序,如果要在A里面使用C,会去直接去创建C的对象,也就是说,是在A类中主动去获取所需要的外部资源C,这种情况被称为正向的。反向就是A类不再主动去获取C,而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向的注入到A类中。

 

说一下垃圾回收机制?

GC 的作用区域:

频繁在新生区收集,很少在养老区收集,几乎不在方法区(永久区/元空间)收集,其中,Java堆是垃圾收集器的工作重点

判断对存活的方法:

1.引用计数法

1、引用计数算法(Reference Counting)比较简单,对每个对象保存一个整型的引用计数器属性。用于记录对象被引用的情况。

2、对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收。

存在一个严重的问题:无法处理循环引用的情况

2.可达性分析算法

该算法的基本思路就是通过一些被称为 引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为(Reference Chain),当一个对象到GC Roots没有任何引用链相连时(即从GC Roots节点到该节点不可达),则证明该对象是不可用的。

相对于引用计数算法而言,可达性分析算法不仅同样具备实现简单和执行高效等特点, 更重要的是该算法可以有效地解决在引用计数算法中循环引用的问题,防止内存泄漏的发生。

垃圾清除算法

1、标记清除算法(Mark-Sweep)

标记阶段是把所有活动对象(可达对象,reachable)都做上标记的阶段。清除阶段是把那些没有标记的对象,也就是非活动对象回收的阶段。

2、标记复制算法(Copying)

将活着的 内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收。

3、标记压缩算法(Mark-Compact)

第一阶段和标记清除算法一样,从根节点开始标记所有被引用对象

第二阶段将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间。

 

分代策略

1、年轻代(Young Gen)

1、年轻代特点:区域相对老年代较小,对象生命周期短、存活率低,回收频繁。

2、这种情况 复制算法的回收整理, 速度是最快的。复制算法的效率只和当前存活对象大小有关,因此很适用于年轻代的回收。而复制算法内存利用率不高的问题,通过hotspot中的两个survivor的设计得到缓解。

2、老年代(Tenured Gen)

老年代特点:区域较大,对象生命周期长、存活率高,回收不及年轻代频繁。

这种情况存在大量存活率高的对象,复制算法明显变得不合适。一般是由 标记-清除或者是标记-清除与标记-清除-整理的混合实现。

 

垃圾收集器

新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge

老年代收集器使用的收集器:Serial Old、Parallel Old、CMS

 

8602adf8a146b44d561da5cc14f2f799.png

Serial收集器(复制算法)

新生代单线程收集器,标记和清理都是单线程,优点是简单高效。

Serial Old收集器(标记-整理算法)

老年代单线程收集器,Serial收集器的老年代版本。

ParNew收集器(停止-复制算法) 

新生代收集器,可以认为是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现。

Parallel Scavenge收集器(停止-复制算法)

并行多线程收集器,追求高吞吐量,高效利用CPU。吞吐量一般为99%, 吞吐量= 用户线程时间/(用户线程时间+GC线程时间)。适合后台应用等对交互相应要求不高的场景。

Parallel Old收集器(停止-复制算法)

Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量优先,使用多线程。

CMS(Concurrent Mark Sweep)收集器(标记-清理算法)

高并发、低停顿,追求最短GC回收停顿时间,cpu占用比较高,响应时间快,停顿时间短,多核cpu 追求高响应时间的选择。

无法清理浮动垃圾,容易产生碎片。

清理过程分为4个步骤,包括:

  1. 初始标记(CMS initial mark)
  2. 并发标记(CMS concurrent mark)
  3. 重新标记(CMS remark)
  4. 并发清除(CMS concurrent sweep)

G1收集器

并行与并发执行,分代收集,空间整合,分为不同的regin区域进行垃圾回收

G1 收集器的运作大致可划分为以下几个步骤:

  1. 初始标记(Initial Marking)
  2. 并发标记(Concurrent Marking)
  3. 最终标记(Final Marking)
  4. 筛选回收(Live Data Counting and Evacuation)

 

Minor GC(新生代GC):

指发生在新生代的垃圾收集动作,Java对象大多存活时间不长,所以Minor GC的发生会比较频繁,回收速度也比较快。触发条件:在新生代的Eedn区满了会触发。

Full GC/Major GC(老年代GC):

指发生在老年代的GC,出现了Full GC,经常会伴随至少一次的Minor GC(不是必然的),Major GC的速度一般会比Minor GC慢10倍以上。

触发条件:

System.gc() 方法的调用,此方法会建议JVM进行Full GC,但JVM可能不接受这个建议,所以不一定会执行。

老年代空间不足,创建的大对象的内存大于老年代空间,导致老年代空间不足,则会发生Full GC。

JDK1.7及以前的永久代空间满了,在JDK1.7以前,HotSpot虚拟机的方法区是永久代实现都得,在永久代中会存放一些Class的信息、常量、静态变量等数据,在永久代满了,并且没有配置CMS GC的情况下就会触发Full GC,在JDK1.8开始移除永久代也是为了减少Full GC的频率。

空间分配担保失败,通过Minor GC后进入老年代的平均大小大于老年代的可用空间,会触发Full GC

 

内存回收机制

对象先在Eden区分配,当Eden区没有足够的空间去分配时,虚拟机会发起一次Minor GC,将存活的对象放到From Survivor区(对象年龄为1)。

当再次发生Minor GC,会将Eden区和From Survivor区一起清理,存活的对象会被移动到To Survivor区(年龄加1)。

这时From Survivor区会和To Survivor区进行交换,然后重复第一步,不过这次第一步中的From Survivor区其实是上一轮中的To Survivor区。

每次移动,对象的年龄就会加1,当年龄到达15时(默认是15,对象晋升老年代的年龄阈值可以通过参数 -XX: MaxTenuringThreshold 设置),会从新生代进入老年代。

 

总结:

1.对象优先在Eden区分配。

2.大对象直接进入老年代(大对象指需要大量连续内存空间的Java对象)。

3.长期存活的对象进入老年代。

 

讲一下布隆过滤器?

它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。

布隆过滤器可以告诉我们 “某样东西一定不存在或者可能存在”

 

业务场景:

解决Redis缓存穿透问题(面试重点)

邮件过滤,使用布隆过滤器来做邮件黑名单过滤

对爬虫网址进行过滤,爬过的不再爬

解决新闻推荐过的不再推荐(类似抖音刷过的往下滑动不再刷到)

 

如何解决缓存击穿问题?

方案一、定时任务主动刷新缓存设计

先将所有可能查询到的数据存入redis,对redis中的数据库定时更新,保证redis永远都会有数据存在,来请求只查redis

 

方案二、使用redis的分布式锁

具体步骤:

1.如果缓存命中直接返回数据集

2.如果缓存没有,则尝试获取分布式锁(有超时设置)如果没有拿到锁,则阻塞当前线程,n秒之后再次尝试获取分布式锁

3.拿到锁之后检查数据是否已经被其他线程放到redis缓存中,如果redis缓存已有,直接返回redis中的数据,释放分布式锁;如果缓存没有被刷新,则查数据库将数据库查询的结果保存到redis缓存中并返回查询结果

 

方案三、普通加jvm的锁查询缓存

如果缓存命中直接返回数据集

如果缓存没有,则尝试JVM锁,

其他线程阻塞拿到锁之后,检查redis是否有数据,以免其他线程已经刷过缓存

如果redis已经有数据,直接返回,并释放锁,返回数据库结束

如果redis没有数据,则查询数据库,并保存到redis缓存中返回数据,释放锁

 

比如:

有s台服务器,用户请求数为n;那么同一时间参数相同的请求最多只会有s次查询打到数据库上,这里s这个常量相当于原来对于数据库来说一个O(n)的操作时间下降到了O(s)

这里可以看出,查询数据库操作的耗时与n的增长无关,只与s有关

 

方案四、jvm缓存+redis缓存的多级缓存

 

1ab3d3eae53d0227758a97db8d49ce4b.png

这种设计,服务器只会在jvm缓存失效,且redis缓存也失效的情况下才会查询数据库,而多个服务器的jvm缓存失效时间是随机值,所以很大程度上避免的同时失效去查库的情况,由于所有服务器jvm缓存同时失效redis缓存也失效的可能性极低,所以数据库上重复的查询会很少

 

如何优化sql查询速度

1.添加索引

经常需要搜索的列上,可以加快搜索的速度;

在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。

在经常需要排序的列上创 建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;

对于中到大型表索引都是非常有效的,但是特大型表的话维护开销会很大,不适合建索引

在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;

避免 where 子句中对宇段施加函数,这会造成无法命中索引。

2.实现细节

1.SQL语句中IN包含的值不应过多;

2.SELECT语句务必指明字段名称,不用*;

3.只查询一条数据的时候,使用limit 1;

4.避免在where子句中对字段进行表达式操作,这样做可能导致索引失效;

5.对于联合索引来说,要遵守最左前缀法则,防止其失效;

6.尽量使用inner join,这样在没有其他过滤条件的情况下MySQL会自动选择小表作为驱动表;

7.对于联合索引来说,如果存在范围查询,比如between、>、<等条件时,会造成后面的索引字段失效。

解决办法: 业务允许的情况下,使用 >= 或者<=  这样不影响索引的使用.;

8.在 where 子句中使用 or 来连接条件,如果or连接的条件有一方没有索引,将导致引擎放弃使用索引而进行全表扫描

解决办法: 将or连接的双方都建立索引,就可以使用. 

9.count 优化     速度:count(*)>count(1)>count(字段)

10.指定查询的索引

use index(索引): 推荐使用指定的索引 (最终用不用该索引,还需要mysql自己判断)

ignore index(索引) : 忽略掉这个索引

force index(索引): 强制使用该索引

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1358159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ES6语法学习】解构赋值

文章目录 引言一、什么是解构赋值1.1什么是解构赋值1.2 数组的解构赋值1.2.1 基本用法1.2.2 默认值1.2.3 剩余参数 1.3 对象的解构赋值1.3.1 基本用法1.3.2 默认值1.3.2 剩余参数 1.4 字符串的解构赋值1.5 函数参数的解构赋值 二、解构赋值的优势和应用场景2.1 代码简化和可读性…

并发程序设计--D2D3exec函数族和守护进程

exec 函数族 背景&#xff1a;fork创建进程之后&#xff0c;子进程和父进程执行相同的代码&#xff0c;但是在实际开发当中&#xff0c;我们希望父子进程执行不同的代码。 作用&#xff1a;执行指定的程序 #include <unistd.h> int execl(const char *path, const cha…

echarts中dataZoom拖拽不起效果

vue3项目中&#xff0c;echarts使用dataZoom进行区域拖动&#xff0c;拖动下图红色框&#xff0c;数据展示无变化拖动功能失效。 原因 vue3中使用了ref或者reactive等初始化图表的变量 //定义 let myChart ref<any>(null); //使用 myChart.value echarts.init(chartR…

京东年度数据报告-2023全年度净水器十大热门品牌销量榜单

近年来&#xff0c;随着科技的不断发展和应用&#xff0c;净水器的技术得到持续创新和提高&#xff0c;产品品质和使用效果不断优化&#xff0c;这也进一步提升了净水器的市场竞争力&#xff0c;2023年&#xff0c;净水器市场的销售成绩呈现增长。 根据鲸参谋平台的数据显示&a…

了解单元测试

一&#xff0c;测试分类 1.1 E2E测试&#xff08;end to end端到端测试&#xff09; 属于黑盒测试。 主要通过测试框架&#xff0c;站在用户测试人员的角度&#xff0c;模拟用户的操作进行页面功能的验证&#xff0c;不管内部实现机制&#xff0c;完全模拟浏览器的行为。&am…

接口自动化—pytest命令行操作

学习目标&#xff1a; 1、pytest的不同的运行方法 2、pytest常见的命令行参数 3、如何添加自定义的pytest命令行参数 学习内容&#xff1a; 1、pytest的不同的运行方法 1.1主要有三种情况的运行方式&#xff1a; 1.1.1没有使用pytest框架&#xff0c;但是要运行包含test…

微信多功能投票小程序源码系统:送礼物+在线充值+票数汇总+创建活动+完整的代码安装包 附带完整的搭建教程

微信已成为人们日常生活中不可或缺的一部分。因此&#xff0c;微信小程序也受到了广大用户的欢迎。在这个背景下&#xff0c;多功能投票小程序应运而生&#xff0c;为各种活动提供了方便快捷的投票方式。本文将介绍一款微信多功能投票小程序源码系统&#xff0c;该系统具有送礼…

Python | Iter/genartor | 一文了解迭代器、生成器的含义\区别\优缺点

前提 一种技术的出现&#xff0c;需要考虑&#xff1a; 为了实现什么样的需求&#xff1b;遇到了什么样的问题&#xff1b;采用了什么样的方案&#xff1b;最终接近或达到了预期的效果。 概念 提前理解几个概念&#xff1a; 迭代 我们经常听到产品迭代、技术迭代、功能迭代…

Apache Doris (六十一): Spark Doris Connector - (1)-源码编译

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你学编程的个人空间-豹哥教你学编程个人主页-哔哩哔哩视频 目录 1. Spark Doris Connector…

开发者必备的 Github 加速工具(截至2024年01月)

开始闲聊前&#xff0c;我要感谢大神小青龍总结的博文&#xff1a;作为程序员不得不知道的几款Github加速神器&#xff0c;给我们介绍了常用&#xff08;较为合规&#x1f604;&#xff09;的加速方法。毕竟 github 是开发者绕不过的宝库。 背景 我用 Github 将近12年&#x…

drf知识--11

补充 # 研究simple-jwt提供的Token类&#xff1a; 1、RefreshToken:生成refresh token的类 2、AccessToken:生成refresh token的类 3、Token&#xff1a;他们俩的父类 4、str(RefreshToken的对象)---得到字符串 refresh token&#xff0c;Token类写了 …

【linux学习】linux概述

1. linux概述 操作系统主要的功能有两个部分&#xff0c;一是更有效率的控制计算机硬件资源&#xff08;主要通过核心来控制&#xff09;&#xff0c;二是为程序设计师提供更容易开发软件的环境&#xff08;系统呼叫提供软件开发环境&#xff09;。linux就是一套操作系统&…

台灯学生用哪个牌子最好?学生护眼台灯最好的品牌推荐

如今的家长对教育十分重视&#xff0c;不仅给孩子提供了各种别致的文具&#xff0c;为了孩子有更好的学习光线&#xff0c;还会购买各种护眼台灯&#xff0c;但各种选择五花八门。从无蓝光、无频闪到柔和光&#xff0c;各种宣传亮点层出不穷……为了为孩子选购一款优质的学习护…

P3704数字表格(莫比乌斯反演)

题目背景 Doris 刚刚学习了 fibonacci 数列。用 fi​ 表示数列的第 i 项&#xff0c;那么 00,11f0​0,f1​1 fn​fn−1​fn−2​,n≥2 题目描述 Doris 用老师的超级计算机生成了一个 nm 的表格&#xff0c; 第 i 行第 j 列的格子中的数是 gcd(i,j)​&#xff0c;其中gcd(…

企业数据治理的三个阶段:从起步到成熟的数据管理之旅

随着数字化时代的到来&#xff0c;企业数据已经成为企业的重要资产和驱动业务发展的重要力量。然而&#xff0c;要想充分利用数据的价值&#xff0c;企业需要对其数据进行有效的管理和治理。本文将对企业数据治理的三个阶段进行详细的探讨&#xff0c;以帮助企业了解其在数据治…

5600U PVE安装WIN10后直通核显

修改PVE系统配置 请先安装相同版本的PVE系统&#xff0c;其他版本如果存在问题请自行查找。 安装过程比较简单&#xff0c;具体方法请自行百度 1. 修改grub启动参数&#xff1a; 修改文件 /etc/default/grub 中 GRUB_CMDLINE_LINUX_DEFAULT 配置&#xff1a; GRUB_CMDLINE_LI…

七款人体感应报警器电路图

人体感应报警器电路图&#xff08;一&#xff09; 人体发出的红外线波长在9&#xff5e;10um之间&#xff0c;属远红外线区。我们利用热释电红外传感器及信号处理集成电路&#xff0c;组装成一个人体红外线感应开关电路报警器&#xff0c;它能依靠人体发出的微量红外线进行开关…

一键减低PNG像素,轻松优化图片质量!

在数字时代&#xff0c;我们每天都要处理大量的图片文件&#xff0c;从网站设计、广告素材到社交媒体图片等。PNG作为一种常用的无损压缩格式&#xff0c;在保证图片质量的同时&#xff0c;也占用了较大的存储空间。为了优化存储空间和提高加载速度&#xff0c;我们需要对PNG图…

获取小红书笔记详情API调用说明(含请求示例参数说明)

前言 小红书&#xff0c;是一个引领全球时尚潮流的社交电商平台。在这里&#xff0c;你可以发现世界各地的优质好物&#xff0c;从美妆护肤、穿搭时尚&#xff0c;到家居生活、旅行美食&#xff0c;一切应有尽有。同时&#xff0c;这里也是一个分享生活点滴的平台&#xff0c;…

CPU平台做视频智能分析,Lnton视频分析平台不仅支持流分析,同时也支持图片分析了

LntonAIServer最新v1.0.09版本支持图片分析了&#xff0c;经过几个月的研发&#xff0c;在原有的视频流分析的基础上&#xff0c;我们终于支持大家都非常期待的图片分析功能了&#xff0c;图片分析的功能加上&#xff0c;能有利于很多场景的展开&#xff0c;比如在烟火、明厨亮…