一个 MVCC 和面试官大战30回合

我,小Y。

此刻,正坐在办公室里等待面试,心情xue微有点忐忑,不知道待会儿老面试官经不经得住我的折磨。

只见一抹光亮闪过,面试官推门而入,我抬头望去,强者的气息铺面而来,没错是那味儿。

看到面试官头上那“傲然矗立”的头发,脑海中止不住幻想他在无数个凌晨于电脑前挑灯夜码的高大形象,一种敬佩感油然而生, 竟忍不住站起来给他敬了个礼。

面试官:有病?

我:没没没,我谢顶反应综合征犯了,面试官好,我是小 Y ,请多多指教。

面试官:哦哦,确实是有病啊,没事,记得吃药就行。我看你简历写你 MySQL 挺懂的,那我先问问你 MySQL 吧。

我:好嘞,您请。

面试官:你知道什么是 MySQL 的酸吗?

这一来就这么猛的吗?脑海中一顿搜索,只能想起张含韵的我喜欢酸的甜这就是真的我之《酸酸甜甜就是我》,算了蒙一个。

我:事务?

面试官:哟,最近好多谐音梗,我特意玩了个英语单词短语梗,脑子转的挺快啊小伙子。

酸,英文 acid,说的就是事务!这都蒙对了,等下就去买彩票!趁这个机会再表现一下!

我:是啊,国外的人就有拼凑单词的习惯,其实事务主要是为了实现 C ,也就是一致性,具体是通过AID,即原子性、隔离性和持久性来达到一致性的目的,所以这四个不应该相提并论,但是他们就想拼成单词,就把它们排好序搞在一起来念。

嘿嘿,这个B装的我有点舒服,果然面试官有点惊讶。

面试官:可以呀,那你知道 MVCC 吧?

我:知道,Multi-Version Concurrency Control (多版本并发控制)。

面试官:能先简短的解释下什么是 MVCC 吗?

我:多版本并发控制,其实指的是一条记录会有多个版本,每次修改记录都会存储这条记录被修改之前的版本,多版本之间串联起来就形成了一条版本链,这样不同时刻启动的事务可以无锁地获得不同版本的数据(普通读)。此时读(普通读)写操作不会阻塞,写操作可以继续写,无非就是多加了一个版本,历史版本记录可供已经启动的事务读取。

(为保持简短,简化了SQL语句,下文也同样简化)

面试官:那你知道事务四种隔离级别吧?

我:读未提交、读已提交、可重复读、可串行化。

面试官:MVCC 用来实现哪几个隔离级别?

我:用来实现读已提交和可重复读。首先隔离级别如果是读未提交的话,直接读最新版本的数据就行了,压根就不需要保存以前的版本。可串行化隔离级别事务都串行执行了,所以也不需要多版本,因此 MVCC 是用来实现读已提交和可重复读的。

面试官:那为什么需要 MVCC ?如果没有 MVCC 会怎样?

我:如果没有 MVCC 读写操作之间就会冲突。想象一下有一个事务1正在执行,此时一个事务2修改了记录A,还未提交,此时事务1要读取记录A,因为事务2还未提交,所以事务1无法读取最新的记录A,不然就是发生脏读的情况,所以应该读记录A被事务2修改之前的数据,但是记录A已经被事务2改了呀,所以事务1咋办?只能用锁阻塞等待事务2的提交,这种实现叫 LBCC(Lock-Based Concurrent Control)。

如果有多版本的话,就不一样了。事务2修改的记录 A,还未提交,但是记录 A 被修改之前的版本还在,此时事务1就可以读取之前的版本数据,这样读写之间就不会阻塞啦,所以说 MVCC 提高了事务的并发度,提升数据库的性能。

面试官:你对这个多版本有没有什么别的理解?

我:(面试官要开始操作我了吗?不过就这,我早有准备!)有点个人的小理解(假装谦虚)。其实这个多版本不是很准确,只是为了便于理解或者说展现出来像多版本的样子而已。

实际上 InnoDB 不会真的存储了多个版本的数据,只是借助 undolog 记录每次写操作的反向操作,所以索引上对应的记录只会有一个版本,即最新版本。只不过可以根据 undolog 中的记录反向操作得到数据的历史版本,所以看起来是多个版本。

面试官:那你能详细的说下 MVCC 是如何实现的吗?

我:您听好啦。

拿上面的insert (1,XX)这条语句举例,成功插入之后数据页的记录上不仅存储 ID 1,name XX,还有 trx_id 和 roll_pointer 这两个隐藏字段:

  • trx_id:当前事务ID。
  • roll_pointer:指向 undo log 的指针。

从图中可以得知此时插入的事务ID是1,此时插入会生成一条 undolog ,并且记录上的 roll_pointer 会指向这条 undolog ,而这条 undolog 是一个类型为TRX_UNDO_INSERT_REC的 log,代表是 insert 生成的,里面存储了主键的长度和值(还有其他值,不提),所以 InnoDB 可以根据 undolog 里的主键的值,找到这条记录,然后把它删除来实现回滚(复原)的效果。因此可以简单地理解 undolog 里面存储的就是当前操作的反向操作,所以认为里面存了个delete 1 就行。

此时事务1提交,然后另一个 ID 为 5 的事务再执行 update NO where id 1 这个语句,此时的记录和 undolog 就如下图所示:

没错,之前 insert 产生的 undolog 没了,insert 的事务提交了之后对应的 undolog 就回收了,因为不可能有别的事务会访问比这还要早的版本了,访问插入之前的版本?访问个寂寞吗?

而 update 产生的 undolog 不一样,它的类型为 TRX_UNDO_UPD_EXIST_REC

此时事务 5 提交,然后另一个 ID 为 11 的事务执行update Yes where id 1 这个语句,此时的记录和 undolog 就如下图所示:

没错,update 产生的 undolog 不会马上删除,因为可能有别的事务需要访问之前的版本,所以不能删。这样就串成了一个版本链,可以看到记录本身加上两条 undolog,这条 id 为 1 的记录共有三个版本。

版本链搞清楚了,这时候还需要知道一个概念 readView,这个 readView 就是用来判断哪个版本对当前事务可见的,这里有四个概念:

  • creator_trx_id,当前事务ID。
  • m_ids,生成 readView 时还活跃的事务ID集合,也就是已经启动但是还未提交的事务ID列表。
  • min_trx_id,当前活跃ID之中的最小值。
  • max_trx_id,生成 readView 时 InnoDB 将分配给下一个事务的 ID 的值(事务 ID 是递增分配的,越后面申请的事务ID越大)

对于可见版本的判断是从最新版本开始沿着版本链逐渐寻找老的版本,如果遇到符合条件的版本就返回

判断条件如下:

  • 如果当前数据版本的 trx_id == creator_trx_id 说明修改这条数据的事务就是当前事务,所以可见。
  • 如果当前数据版本的 trx_id < min_trx_id,说明修改这条数据的事务在当前事务生成 readView 的时候已提交,所以可见。
  • 如果当前数据版本的 trx_id 大小在 min_trx_id 和 max_trx_id 之间,此时 trx_id 若在 m_ids 中,说明修改这条数据的事务此时还未提交,所以不可见,若不在 m_ids 中,表明事务已经提交,可见。
  • 如果当前数据版本的 trx_id >= max_trx_id,说明修改这条数据的事务在当前事务生成 readView 的时候还未启动,所以不可见(结合事务ID递增来看)。

来看一个简单的案例,练一练上面的规则。

读已提交隔离级别下的MVCC

现在的隔离级别是读已提交

假设此时上文的事务1已经提交,事务 5 已经执行,但还未提交,此时有另一个事务在执行update YY where id 2,也未提交,它的事务 ID 为 6,且也是现在最大的事务 ID。

现在有一个查询开启了事务,语句为select name where id 1,那么这个查询语句:

  • 此时 creator_trx_id 为 0,因为一个事务只有当有修改操作的时候才会被分配事务 ID。
  • 此时 m_ids 为 [5,6],这两个事务都未提交,为活跃的。
  • 此时 min_trx_id,为 5。
  • 此时 max_trx_id,为 7,因为最新分配的事务 ID 为 6,那么下一个就是7,事务 ID 是递增分配的。

由于查询的是 ID 为 1 的记录,所以先找到 ID 为 1 的这条记录,此时的版本如下:

和上面的图一样

此时最新版本的记录上 trx_id 为 5,不比 min_trx_id 小,在 m_ids 之中,表明还是活跃的,未提交,所以不可访问,根据 roll_pointer 找到上一个版本。

于是找到了图上的那条 undolog,这条log上面记录的 trx_id 为 1,比 min_trx_id 还小,说明在生成 readView 的时候已经提交,所以可以访问,因此返回结果 name 为 XX。

然后事务 5 提交

此时再次查询 select name where id 1,这时候又会生成新的 readView

  • 此时 creator_trx_id 为 0,因为还是没有修改操作。
  • 此时 m_ids 为 [6],因为事务5提交了。
  • 此时 min_trx_id,为 6。
  • 此时 max_trx_id,为 7,此时没有新的事务申请。

同样还是查询的是 ID 为 1 的记录,所以还是先找到 ID 为 1 的这条记录,此时的版本如下(和上面一样,没变):

此时最新版本的记录上 trx_id 为 5,比 min_trx_id 小,说明事务已经提交了,是可以访问的,因此返回结果 name 为 NO。

这就是读已提交的 MVCC 操作,可以看到一个事务中的两次查询得到了不同的结果,所以也叫不可重复读。

可重复读隔离级别下的MVCC

现在的隔离级别是可重复读

可重复读和读已提交的 MVCC 判断版本的过程是一模一样的,唯一的差别在生成 readView 上

上面的读已提交每次查询都会重新生成一个新的 readView ,而可重复读在第一次生成 readView 之后的所有查询都共用同一个 readView 。

也就是说可重复读只会在第一次 select 时候生成一个 readView ,所以一个事务里面不论有几次 select ,其实看到的都是同一个 readView 。

套用上面的情况,差别就在第二次执行select name where id 1,不会生成新的 readView,而是用之前的 readView,所以第二次查询时:

  • m_ids 还是为 [5,6],虽说事务 5 此时已经提交了,但是这个readView是在事务5提交之前生成的,所以当前还是认为这两个事务都未提交,为活跃的。
  • 此时 min_trx_id,为 5。

(对于判断过程有点卡顿的同学可以再拉上去看看,判断版本的过程和读已提交一致)。

所以在可重复级别下,两次查询得到的 name 都为 XX,所以叫可重复读

说完之后,我对面试官挑了挑眉。

面试官瞥了我一眼:可以,那按你这么说其实 undolog 算是热点资源,多个事务不就会争抢 undolog 了吗?

我:对呀,所以为了提高 undolog 的写入性能,每个事务都有属于自己的 undolog 页面链表,这样就提高了写入并发度啦,再细一点就是 insert 类型的 undolog 和 update 类型的 undolog 属于不同的链表。

面试官:还能细吗?

我:再细一点就是普通表和临时表各有一条 insert 类型的 undolog 和 update 类型的 undolog ,所以最多一个事务可以有四条 undolog 页面链表,之所以分普通表和临时表是因为普通表的 undolog 写入是需要记录到redolog 中的需要保证崩溃恢复,而临时表则不需要记录,反正就是临时的。

面试官:对了,你上面说 insert 和 update ,那 delete 呢?

我:delete 其实是属于 update 的,不过分了好几种情况,反正 delete 只会给记录上打个标记,表明这条记录被删除了,不会马上删除这条记录,因为记录还得存着给别的事务作为版本链访问呢。

面试官:那这条被删除的记录就永远存在了?

我:不会的,后台有一个 purge 线程,如果探测出当前没有事务会访问这个记录了,就会把它真正的删除。

面试官:你这么细,应该没有女朋友的吧?

我:(???,不对,面试官应该没有人身攻击我,只是说我天天刻苦学习,没时间找女朋友,但是我还是有点不爽)没呢,面试官您头发这么多,应该也还没找到吧?

“我在仰望,月亮之上....”,此时面试官手机响起。

面试官:“喂,亲爱的,来了来了,马上下班了,待会老地方见哈。”那啥我有点事,你先回去吧。

我:(???小丑竟是我自己)好嘞好嘞。

面试官:对了,这一面还没结束,undolog看你挺熟的,下次详细问你,还有 MySQL 锁啊我都还没问,等通知下次再来吧。

我:(还给我布置家庭作业呢?)我一定回去好好准备准备,等待您的宠幸。

这老面试官可以,竟然没折磨到他,等着,下次 undolog 和 MySQL 锁我一定好好招待他!


个人文章都汇总链接:https://blog.nowcoder.net/n/77142a8f2001435a9743cf7d8d888cb2

今天的分享到此结束,等我下篇哈,如果觉得文章不错。来个点赞、在看、分享三连哟!

我是yes,从一点点到亿点点,我们下篇见。

#面经#
全部评论
还好今天面试官问我知不知道mvcc我直接说不知道,躲过一劫🤭
3 回复 分享
发布于 2021-06-19 00:46
八股王就是你了
2 回复 分享
发布于 2021-06-18 20:50
有外国教材那味了
1 回复 分享
发布于 2021-06-19 01:12
老哥,最近打算翻一翻发现汇总链接失效了
点赞 回复 分享
发布于 2022-06-13 23:58
卷王
点赞 回复 分享
发布于 2022-03-02 13:31
对于已提交读的MVCC实现有点疑惑:既然已提交读的概念是已经提交的数据都能读到。那为什么这种情况下数据读不到   “如果当前数据版本的 trx_id >= max_trx_id,说明修改这条数据的事务在当前事务生成 readView 的时候还未启动,所以不可见(结合事务ID递增来看)。”  如果当前数据版本 trx_id >= max_trx_id 但是该版数据已经提交了,那么当前事务就应该能读到这条数据吧?
点赞 回复 分享
发布于 2021-08-17 18:39
感谢参与【创作者计划3期·技术干货场】!欢迎更多牛油来写干货,瓜分总计20000元奖励!!技术干货场活动链接:https://www.nowcoder.com/link/czz3jsgh3(参与奖马克杯将于每周五结算,敬请期待~)
点赞 回复 分享
发布于 2021-07-09 11:22
你好,请教下一个事务最多有四条undologo链表什么意思,不应该两个吗?
点赞 回复 分享
发布于 2021-06-24 17:10
读已提交下的MVCC中的举例说明中的事务6怎么没有在图片中和分析汇总体现出来?请教一下
点赞 回复 分享
发布于 2021-06-21 17:38
真的有这么厉害的人吗
点赞 回复 分享
发布于 2021-06-20 20:20
卷王,在下佩服
点赞 回复 分享
发布于 2021-06-20 13:23
太细了
点赞 回复 分享
发布于 2021-06-20 13:04
****,淫才啊🤭😱😱
点赞 回复 分享
发布于 2021-06-19 18:43
我是混子,我还以为是架构的那个呢
点赞 回复 分享
发布于 2021-06-19 11:04
就冲你码这么多字,我也要给个👍
点赞 回复 分享
发布于 2021-06-19 10:50
你这么细?恕我想歪了🤣
点赞 回复 分享
发布于 2021-06-19 09:40
放以前不得中个状元
点赞 回复 分享
发布于 2021-06-18 23:40
期待锁,间隙锁 临键锁
点赞 回复 分享
发布于 2021-06-18 20:04
好家伙
点赞 回复 分享
发布于 2021-06-18 19:57
yes!
点赞 回复 分享
发布于 2021-06-18 14:17

相关推荐

总结:面了一个小时,前半段问项目,后半段问八股,两道编程题。面试官很热情,介绍了半天他们的业务,像是在汇报哈哈哈哈。八股部分1.单例模式有用过吗,怎么实现的(不知道怎么实现)回答:用得比较多的地方是数据库连接池,全局只能有一个连接池,并且提供全局访问。以下是搜索结果:有五种经典的实现方式。第一种是饿汉式(线程安全)他在类加载的时候就立即初始化实例,使用场景是实例占用资源少,且频繁使用。第二种是懒汉式(非线程安全)延迟初始化,在使用的时候,如果没有这个实例才初始化,在多线程环境下会创建多个实例。第三种是线程安全懒汉式,通过synchronized保证线程安全,但性能差。(因为锁的粒度很粗)不建议高频调用。第四种是双重检查锁(DCL)。特点是延迟初始化,并且线程安全第五种是静态内部类(推荐)。特点是利用类加载机制保证线程安全,延迟初始化且无锁。2.JVM运行时数据区回答:有堆,栈,方法区。堆存储对象实例,数组;栈存储线程的调用栈帧;方法去存储对象信息和方法信息。3.事务ACID了解吗回答:原子性,持久性,一致性,隔离性。1.原子性由undolog实现2.隔离性由锁或者MVCC实现(吟唱一下隔离性的四个级别)3.持久性由redolog实现4.一致性由前三者一起保证实现。场景业务题1.在一个发优惠券的场景,我有一个10w行的用户数据表,要取出里面的用户信息放入模型中,返回优惠券的结果,(模拟用户领券的过程)。我需要做的是,验证这些数据是否满足一定的断言(例如面额超过50块,补贴力度过大)。由于一台机器的内存不足以存放这些数据,你有四台机器,请你设计一个批量请求的工具,以分布式的方式去跑这些数据,你会做那些设计?回答:我也没听太懂这些问题。以下是搜索结果。我将设计一个分布式批量处理工具来解决发券场景中的大数据验证问题,核心目标是实现高效分片处理、动态负载均衡、分布式断言校验和结果聚合。以下是详细设计方案:整体架构设计核心组件设计1.分布式协调器(Coordinator)部署在Master节点,负责全局调度2.工作节点(Worker)部署在4台工作机器,负责实际处理3.断言验证引擎该设计可实现10w用户数据的分布式处理,核心优势:1.&nbsp;横向扩展&nbsp;:通过增加Worker节点可线性提升处理能力2.&nbsp;故障容忍&nbsp;:自动重试和检查点机制保证可靠性3.&nbsp;资源优化&nbsp;:流式处理避免内存溢出4.&nbsp;实时监控&nbsp;:全过程可视化跟踪2.饿了么的搜索功能,请你针对这个搜索功能写一些功能点。比如输入奶茶关键词,返回一些结果。回答:我只回答了搜索框不能为空,对返回结果进行排序等等。以下是搜索结果。1.搜索前引导功能a.热词推荐i.功能描述:搜索框下方动态展示当前商圈热门关键词(如奶茶,果茶)ii.奶茶示例:用户点击奶茶热词,直接跳转到相关商品列表页b.历史搜索i.功能描述&nbsp;:根据用户过往搜索记录(如“芋泥奶茶”)生成个性化推荐。ii.数据支撑&nbsp;:历史搜索订单转化率仅次于商家直达c.场景化引导i.功能描述​:分时段(早餐/下午茶)推送关联词(如下午茶时段优先显示“奶茶+甜品”组合)。d.语音/图像搜索i.​功能描述​:支持语音输入“奶茶”或拍摄奶茶图片触发搜索,系统自动转文字并匹配商品。2.关键词处理功能a.​智能纠错与联想​i.功能描述​:自动纠正拼写错误(如“奶车→奶茶”),并联想高频词(如“奶茶→珍珠奶茶”“芝士奶盖”)。ii.技术实现​:基于搜索日志构建纠错词库与拼音转换模型b.​同义词与品类扩展​i.​功能描述​:搜索“奶茶”时同步召回“果茶”“乳茶”等同品类商品。c.​意图识别​d.​功能描述​:i.若用户多次搜索“低卡奶茶”,优先展示低糖商品;ii.若搜索“奶茶+外卖速度”,则突出配送时效快的商家。3.搜索结果展示功能a.​多维度排序​i.​排序逻辑​:综合销量(70%)、评分(20%)、配送速度(10%)等权重生成列表。ii.​奶茶示例​:高销量“喜茶”排列在低销量小众品牌前。b.​分层筛选器​i.​筛选条件​:ii.价格区间(如“10-20元”);iii.口味(“芋泥”“黑糖”);iv.商家服务(“免配送费”“会员折扣”)。c.​商家直达与商品级搜索​i.​功能描述​:ii.输入“奈雪の茶”直接进入店铺页;iii.搜索“霸气葡萄”显示该单品而非全店商品。d.​商业化融合​i.​功能描述​:在结果页插入“奶茶排行榜”或限时优惠活动(如“第二杯半价”)。4.搜索后优化功能a.​个性化结果缓存​i.​功能描述​:用户多次搜索“奶茶”后,首页历史搜索栏固定显示该关键词。b.​搜索分析看板​c.​后台功能​:统计“奶茶”搜索量、点击率、转化率,指导商家优化菜品命名(如将“红茶拿铁”改为“鸳鸯奶茶”)。3.测试人员除了写测试用例之外,还要做那些事情?1.会参与需求的分析与测试策略制定a.&nbsp;参与需求评审会议,分析需求的可测试性b.&nbsp;指定测试计划2.测试设计和用例开发a.测试场景建模b.测试用例编写3.测试执行与缺陷管理a.分层测试实施(单元,集成,系统测试)b.缺陷全生命周期管理4.质量评估与报告输出a.质量指标分析b.测试报告编制5.自动化测试实施a.接口自动化b.UI自动化6.跨团队协作a.开发写作b.产品沟通7.测试过程改进8.技术研究与创新笔试题1.SQL题目:用sql找出不同课程的成绩的第二名和第三名WITH&nbsp;RankedScores&nbsp;AS&nbsp;(SELECTstudent_id,course_id,score,RANK()&nbsp;OVER&nbsp;(PARTITION&nbsp;BY&nbsp;course_id&nbsp;ORDER&nbsp;BY&nbsp;score&nbsp;DESC)&nbsp;AS&nbsp;rankFROM&nbsp;scores)SELECTcourse_id,student_id,score,rankFROM&nbsp;RankedScoresWHERE&nbsp;rank&nbsp;IN&nbsp;(2,&nbsp;3)ORDER&nbsp;BY&nbsp;course_id,&nbsp;rank;2.LeetCode梦的开始:两数之和反问环节1.你们的业务内容回答:主要负责搜索功能和营销功能,搜索就是饿了么的搜索框部分,营销主要负责爆红包等等。日常还要做一些系统的压力测试,以及与其他团队一起做集成测试。年度还会做测试平台开发,质量和效率提升的OKR。2.工作节奏回答:9点半上班,周一到周四可能下班晚一点,周五正常6点下班,周末双休。3.开发技术栈回答:主要是Java
查看11道真题和解析
点赞 评论 收藏
分享
06-12 11:51
已编辑
门头沟学院 Java
1.&nbsp;反射的原理是什么?2.&nbsp;类加载时,类和实例分别加载到哪里?3.&nbsp;什么是好的编程方法或方案?4.&nbsp;SQL&nbsp;语句优化有哪些方法?5.&nbsp;订单生成&nbsp;ID&nbsp;的实现方式是什么?6.&nbsp;如何处理时间回拨问题?7.&nbsp;雪花算法的基本原理是什么?8.&nbsp;如何设计一个简单的&nbsp;IOC&nbsp;容器?9.&nbsp;自动装箱和拆箱的底层实现是什么?10.&nbsp;Java&nbsp;中的线程安全是什么意思?11.&nbsp;什么是&nbsp;TLAB(Thread&nbsp;Local&nbsp;Allocation&nbsp;Buffer)?12.&nbsp;NIO&nbsp;的基本概念是什么?13.&nbsp;ConcurrentHashMap&nbsp;中锁的机制是什么?14.&nbsp;一条&nbsp;SQL&nbsp;语句在&nbsp;MySQL&nbsp;中的执行过程是怎样的?15.&nbsp;MySQL&nbsp;中事务的日志记录是如何实现的?16.&nbsp;如何通过代码实现死锁?17.&nbsp;接口和抽象类的区别是什么?18.&nbsp;接口和抽象类在设计模式中的体现有哪些?19.&nbsp;String、StringBuilder&nbsp;和&nbsp;StringBuffer&nbsp;的区别是什么?20.&nbsp;final&nbsp;关键字的作用是什么?21.&nbsp;THREAD&nbsp;LOCAL&nbsp;可能引发的内存泄漏问题是什么?22.&nbsp;THREAD&nbsp;LOCAL&nbsp;的应用场景有哪些?23.&nbsp;如何将父线程的&nbsp;THREAD&nbsp;LOCAL&nbsp;值传递给子线程?24.&nbsp;对&nbsp;Java&nbsp;面向对象的理解是什么?25.&nbsp;面向对象和面向过程的区别是什么?26.&nbsp;Java&nbsp;中创建对象的方式有哪些?27.&nbsp;Java&nbsp;中序列化与反序列化的概念是什么?28.&nbsp;Redis&nbsp;中使用哈希存储对象和直接使用字符串存储对象的区别是什么?29.&nbsp;Java&nbsp;中参数传递是按值传递还是按引用传递?30.&nbsp;多继承可能带来的问题是什么?31.&nbsp;方法重载与方法重写的区别是什么?32.&nbsp;Java&nbsp;内部类的概念和作用是什么?33.&nbsp;JDK&nbsp;8&nbsp;的新特性有哪些?34.&nbsp;JRE&nbsp;和&nbsp;JDK&nbsp;的区别是什么?35.&nbsp;JDK&nbsp;中常用的工具类有哪些?36.&nbsp;Hashcode&nbsp;的作用是什么?37.&nbsp;TreeSet&nbsp;集合在加入一个对象时如何判断该对象是否存在?38.&nbsp;是否可能两个不相等的对象有相同的哈希值?39.&nbsp;Java&nbsp;中的&nbsp;hashCode&nbsp;和&nbsp;equals&nbsp;方法有什么区别?40.&nbsp;什么是&nbsp;Java&nbsp;中的动态代理?41.&nbsp;动态代理与静态代理的区别是什么?42.&nbsp;注解的原理是什么?43.&nbsp;SPI&nbsp;机制的作用是什么?44.&nbsp;泛型的作用是什么?45.&nbsp;什么是泛型擦除?46.&nbsp;深拷贝和浅拷贝的区别是什么?47.&nbsp;Integer&nbsp;类型的缓存池是如何工作的?48.&nbsp;Java&nbsp;程序的运行过程是怎样的?49.&nbsp;new&nbsp;一个&nbsp;String&nbsp;类型的对象时会创建多少个对象?50.&nbsp;final、finally&nbsp;和&nbsp;finalize&nbsp;的区别是什么?51.&nbsp;Java&nbsp;的基本类型有哪些?52.&nbsp;静态方法和实例方法的区别是什么?53.&nbsp;for-each&nbsp;循环实现的接口或集合类型是什么?54.&nbsp;RandomAccess&nbsp;接口的作用是什么?55.&nbsp;迭代器(Iterator)的工作原理是什么?56.&nbsp;ArrayList&nbsp;和&nbsp;LinkedList&nbsp;的区别是什么?57.&nbsp;为什么需要&nbsp;ArrayList&nbsp;而不是直接使用数组?58.&nbsp;数组和链表在&nbsp;Java&nbsp;中的区别是什么?59.&nbsp;ArrayList&nbsp;的扩容机制是怎样的?60.&nbsp;ArrayList&nbsp;的缺点有哪些?如何使其线程安全?61.&nbsp;如何使一个集合不可修改?62.&nbsp;使用&nbsp;HashMap&nbsp;时有哪些提升性能的技巧?63.&nbsp;什么是哈希碰撞?在&nbsp;HashMap&nbsp;中如何解决哈希碰撞?64.&nbsp;HashMap&nbsp;的&nbsp;put&nbsp;方法执行流程是怎样的?65.&nbsp;为什么&nbsp;HashMap&nbsp;在扩容时总是以&nbsp;2&nbsp;的&nbsp;n&nbsp;次方倍增长?66.&nbsp;ConcurrentHashMap&nbsp;在&nbsp;get&nbsp;方法中是否需要加锁?67.&nbsp;为什么&nbsp;HashMap&nbsp;不支持&nbsp;key&nbsp;或&nbsp;value&nbsp;为&nbsp;null?68.&nbsp;Java&nbsp;中如何创建多线程?69.&nbsp;线程池的工作原理是什么?70.&nbsp;Java&nbsp;中的线程是如何进行通信的?71.&nbsp;join&nbsp;方法的原理是什么?72.&nbsp;主线程如何知道子线程创建成功?73.&nbsp;反射的原理是什么?74.&nbsp;Java&nbsp;内存模型是什么?如何保证可见性和有序性?75.&nbsp;final&nbsp;关键字是否能够保证变量的可见性?
点赞 评论 收藏
分享
评论
77
261
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务