过分高估自己了,每日5题,完成不了,时间不够,因为对每一个知识点深入查缺补漏,然后记住需要的时间很多

1、详细说说类加载器

启动类加载器(Bootstrap Class Loader):

启动类加载器负责加载存放在<JAVA HOME>\lib目录,或者被Xbootclasspath参数所指定的路径中存放的,而且是java虚拟机能够识别的(按照文件名识别,如rt.jar、tools.jar,名字不符合的类库即使放在lib目录也不会被加载)类库加载到虚拟机的内存中。启动类加载器无法被Java程序直接引用,用户在编写自定义类加载器的时候,如果需要把加载请求委派给启动类加载器取处理,那直接使用null代替即可

扩展类加载器(Extension Class Loader):

这个类加载器是在类sum.misc.Launcher$ExtClassLoader中以Java代码的形式实现的。它负责加载<JAVA_HOME>\lib\ext目录中,或者被java.ext.dirs系统变量所指定的路径中所有的类库

应用程序类加载器(Application Class Loader):

这个类加载器由sum.miscLauncher$AppClassLoader来实现。由于应用程序类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以有些场合也称它位“系统类加载器”。它负责加载用户类路径(ClassPath)上所有的类库,开发者同样可以直接在代码中使用这个类加载器。如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中的默认类加载器。

2、Synchronize关键字的底层原理

synchronized 关键字底层原理属于 JVM 层面。

第一种情况:synchronized 同步语句块的情况

public class SynchronizedDemo {public void method() {synchronized (this) {System.out.println("synchronized 代码块");}}
}

通过 JDK 自带的 javap 命令查看 SynchronizedDemo 类的相关字节码信息:首先切换到类的对应目录执行 javac SynchronizedDemo.java 命令生成编译后的 .class 文件,然后执行javap -c -s -v -l SynchronizedDemo.class

从上面我们可以看出:synchronized 同步语句块的实现使用的是 monitorentermonitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。

当执行 monitorenter 指令时,线程试图获取锁也就是获取 对象监视器 monitor 的持有权。

在 Java 虚拟机(HotSpot)中,Monitor 是基于 C++实现的,由ObjectMonitor实现的。每个对象中都内置了一个 ObjectMonitor对象。

另外,wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

在执行monitorenter时,会尝试获取对象的锁,如果锁的计数器为 0 则表示锁可以被获取,获取后将锁计数器设为 1 也就是加 1。

如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外一个线程释放为止。

第二种情况:synchronized 修饰方法的的情况

public class SynchronizedDemo2 {public synchronized void method() {System.out.println("synchronized 方法");}
}

synchronized 修饰的方法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是 ACC_SYNCHRONIZED 标识,该标识指明了该方法是一个同步方法。JVM 通过该 ACC_SYNCHRONIZED 访问标志来辨别一个方法是否声明为同步方法,从而执行相应的同步调用。

如果是实例方法,JVM 会尝试获取实例对象的锁。如果是静态方法,JVM 会尝试获取当前 class 的锁。

总结:

synchronized 同步语句块的实现使用的是 monitorentermonitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。

synchronized 修饰的方法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是 ACC_SYNCHRONIZED 标识,该标识指明了该方法是一个同步方法。

不过两者的本质都是对对象监视器 monitor 的获取。

答案参考javaguide

衍生问题:

  • synchronized的原理(从ObjectMonitor角度分析)

3、MyISAM和InnoDB的区别

  1. InnoDB 支持事务,MyISAM 不支持事务。这是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一;

  2. InnoDB 支持外键,而 MyISAM 不支持。对一个包含外键的 InnoDB 表转为 MYISAM 会失败;

  3. InnoDB 是聚簇索引,MyISAM 是非聚簇索引。聚簇索引的文件存放在主键索引的叶子节点上,因此 InnoDB 必须要有主键,通过主键索引效率很高。但是非聚簇需要两次查询,先查询到主键,然后再通过主键查询到数据。而 MyISAM 是非聚集索引,值得注意的是数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。

    InnoDB的非聚簇索引data域存储相应记录 主键的值 ,而MyISAM索引记录的是 地址

  4. InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。而MyISAM 用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;

  5. InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限。这也是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一;

答案参考知乎:

https://www.zhihu.com/question/20596402

4、为什么Redis比较快,单线程就一定快吗?

第一个问题为什么redis这么快

  • 基于内存实现

我们都知道内存读写是比磁盘读写快很多的。Redis是基于内存存储实现的数据库,相对于数据存在磁盘的数据库,就省去磁盘磁盘I/O的消耗。MySQL等磁盘数据库,需要建立索引来加快查询效率,而Redis数据存放在内存,直接操作内存,所以就很快。

  • 高效的数据结构

我们知道,MySQL索引为了提高效率,选择了B+树的数据结构。其实合理的数据结构,就是可以让你的应用/程序更快。

redis设计到的数据结构如下:

SDS简单动态字符串

1、常数复杂度获取字符串长度

由于 len 属性的存在,我们获取 SDS 字符串的长度只需要读取 len 属性,时间复杂度为 O(1)。而对于 C 语言,获取字符串的长度通常是经过遍历计数来实现的,时间复杂度为 O(n)

2、减少修改字符串的内存重新分配次数

在C语言中,修改一个字符串,需要重新分配内存,修改越频繁,内存分配就越频繁,而分配内存是会消耗性能的。而在Redis中,SDS提供了两种优化策略:空间预分配和惰性空间释放。

  • 空间预分配:对字符串进行空间扩展的时候,扩展的内存比实际需要的多,这样可以减少连续执行字符串增长操作所需的内存重分配次数。
  • 惰性空间释放:当SDS缩短时,不是回收多余的内存空间,而是用free记录下多余的空间。后续再有修改操作,直接使用free中的空间,减少内存分配。

哈希

Redis 作为一个K-V的内存数据库,它使用用一张全局的哈希来保存所有的键值对。这张哈希表,有多个哈希桶组成,哈希桶中的entry元素保存了*key*value指针,其中*key指向了实际的键,*value指向了实际的值。

哈希表查找速率很快的,有点类似于Java中的HashMap,它让我们在O(1) 的时间复杂度快速找到键值对。首先通过key计算哈希值,找到对应的哈希桶位置,然后定位到entry,在entry找到对应的数据。

Redis为了解决哈希冲突,采用了链式哈希。链式哈希是指同一个哈希桶中,多个元素用一个链表来保存,它们之间依次用指针连接。

为了保持高效,Redis 会对哈希表做rehash操作,也就是增加哈希桶,减少冲突。为了rehash更高效,Redis还默认使用了两个全局哈希表,一个用于当前使用,称为主哈希表,一个用于扩容,称为备用哈希表。

跳跃表

跳跃表是Redis特有的数据结构,它其实就是在链表的基础上,增加多级索引,以提高查找效率。跳跃表的简单原理图如下

  • 每一层都有一条有序的链表,最底层的链表包含了所有的元素。
  • 跳跃表支持平均 O(logN),最坏 O(N)复杂度的节点查找,还可以通过顺序性操作批量处理节点。

压缩列表ziplist

压缩列表ziplist是列表键和字典键的的底层实现之一。它是由一系列特殊编码的内存块构成的列表, 一个ziplist可以包含多个entry, 每个entry可以保存一个长度受限的字符数组或者整数,如下:

由于内存是连续分配的,所以遍历速度很快

各个字段详细解释见redis笔记

  • 合理的数据编码

Redis支持多种数据基本类型,每种基本类型对应不同的数据结构,每种数据结构对应不一样的编码。为了提高性能,Redis设计者总结出,数据结构最适合的编码搭配。

Redis是使用对象(redisObject)来表示数据库中的键值,当我们在 Redis 中创建一个键值对时,至少创建两个对象,一个对象是用做键值对的键对象,另一个是键值对的值对象。

typedef struct redisObject{//类型unsigned type:4;//编码unsigned encoding:4;//指向底层数据结构的指针void *ptr;//引用计数int refcount;//记录最后一次被程序访问的时间unsigned lru:22;
}robj

redisObject中,type 对应的是对象类型,包含String对象、List对象、Hash对象、Set对象、zset对象。encoding 对应的是编码。

  • String:如果存储数字的话,

    int 编码:保存的是可以用 long 类型表示的整数值。

    raw 编码:保存长度大于44字节的字符串(redis3.2版本之前是39字节,之后是44字节)。

    embstr 编码:保存长度小于44字节的字符串(redis3.2版本之前是39字节,之后是44字节)。

  • List:

    当同时满足下面两个条件时,使用ziplist(压缩列表)编码:

    1、列表保存元素个数小于512个

    2、每个元素长度小于64字节

    不能满足这两个条件的时候使用 linkedlist 编码。

  • Hash:

    当同时满足下面两个条件时,使用ziplist(压缩列表)编码:

    1、列表保存元素个数小于512个

    2、每个元素长度小于64字节

    不能满足这两个条件的时候使用 hashtable 编码

  • Set:

    当集合同时满足以下两个条件时,使用 intset 编码:

    1、集合对象中所有元素都是整数

    2、集合对象所有元素数量不超过512

    不能满足这两个条件的就使用 hashtable 编码。

  • Zset:

    当有序集合对象同时满足以下两个条件时,对象使用 ziplist 编码:

    1、保存的元素数量小于128;

    2、保存的所有元素长度都小于64字节。

    不能满足上面两个条件的使用 skiplist 编码。

  • 合理的线程模型

单线程模型:避免了上下文切换

Redis是单线程的,其实是指Redis的网络IO和键值对读写是由一个线程来完成的。但Redis的其他功能,比如持久化、异步删除、集群数据同步等等,实际是由额外的线程执行的。

Redis的单线程模型,避免了CPU不必要的上下文切换和竞争锁的消耗。也正因为是单线程,如果某个命令执行过长(如hgetall命令),会造成阻塞。Redis是面向快速执行场景的内存数据库,所以要慎用如lrange和smembers、hgetall等命令。

I/O 多路复用

多路I/O复用技术可以让单个线程高效的处理多个连接请求,而Redis使用用epoll作为I/O多路复用技术的实现。并且Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。

  • 虚拟内存机制

Redis的VM(虚拟内存)机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。

答案整理参考博客地址:

  • https://blog.csdn.net/hollis_chuang/article/details/118865058
  • https://www.cnblogs.com/ysocean/p/9102811.html#_label0
  • https://www.codenong.com/cs106843764/

第二个问题单线程就一定快吗?

不是的

举例说明:

  • 当你往 Redis 中写入大量数据后,就可能发现操作有时候会突然变慢了,可能是由于哈希表的冲突问题和 rehash 可能带来的操作阻塞。(当然redis为了解决这个问题提出了相应的解决方案)
  • 我们在进行AOF日志和RDB日志文件的时候就可能由于数据量过大导致fork子进程的时候导致主线程阻塞,从而让其他操作变慢

5、三次握手四次挥手过程

三次握手过程

三次握手(Three-way Handshake)指客户端和服务器建立一个TCP连接时,双方总共需要发送3个报文段。目的:

  • 确认双方的接收能力和发送能力是否正常
  • 同时指定双方的初始化序列号(ISN)为后面的可靠性传送做准备

刚开始服务端处于监听状态,进行三次握手由客户端主动发起:

  1. 第一次握手:客户端给服务端发一个 连接请求报文段,头部指明SYN=1,以及初始化序列号 ISNseq=x)。此报文段不能携带数据,但要消耗掉一个序号。随后客户端进入 SYN_SENT (同步发送)状态。
  2. 第二次握手:服务端收到客户端的 连接请求报文段之后,向客户端发送连接确认报文段,头部指明SYN=1ACK=1,确认号(ack)为x+1,并且也选择一个初始化序列号y。随后服务器进入 SYN_RCVD (同步接收)的状态。
  3. 第三次握手:客户端收到服务端的 连接确认报文段之后,会向服务端回送一个确认报文段,头部指明ACK=1,确认号ack=y+1,序号seq=x+1,该报文段可以携带数据,不携带数据则不消耗序号。随后客户端进入 ESTABLISHED (连接已建立)状态。待服务器收到客户端发送的 ACK 报文段也会进入 ESTABLISHED 状态,完成三次握手。

四次挥手的过程

由于客户端或服务端均可主动发起挥手动作,因此这里称主动方和被动方。四次挥手(Four-way handshake)指主动方和和被动方断开 TCP连接需要发送四个包报文段。挥手前,双方都处于ESTABLISHED 状态,假如是客户端先发起关闭请求,对应过程如下:

  • 第一次挥手:客户端向服务端发送一个连接释放报文段,头部指明FIN=1,序号seq=u。并停止发送数据,主动关闭TCP连接。随后客户端进入 FIN_WAIT1 (终止等待1)状态,等待服务端的确认。
  • 第二次挥手:服务端收到客户端发来的连接释放报文段后,回送 确认报文段,头部指明ACK=1,确认号ack=u+1,序号seq=v,随后服务端进入 CLOSE_WAIT(关闭等待) 状态。客户端收到服务端的确认报文段后,进入FIN_WAIT2(终止等待2)状态,等待服务端发出的连接释放报文段
  • 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,向客户端发送连接释放报文段,头部指明FIN=1ACK=1,序号seq=w,确认号ack=u+1,随后服务端进入LAST_ACK(最后确认)状态,等待客户端的确认报文段
  • 第四次挥手:客户端收到连接释放报文段之后,同样向服务端发出确认报文段,头部指明ACK=1seq=u+1ack=w+1,此时客户端进入 TIME_WAIT 状态。服务端收到客户端的确认报文段之后,进入 CLOSED 状态。客户端必须经过 2*MSL 后才进入 CLOSED 状态。此时TCP连接已经完全释放。

备战秋招2022/3/28相关推荐

  1. 备战秋招 |《百面机器学习》算法+leetcode开班报名!

    算法面试刷题班推荐: 以<百面机器学习>为教材 结合leetcode筛选刷题 秋招已经开始了!时间紧迫,也许别人已经得到offer了,你却还在不知所措?(文末重金招聘讲师) 六月份基本都是 ...

  2. Github | 备战秋招,最全面试题集合!

    最近很多大厂已经开始开始了校招提前批,2020届的同学们可以赶紧启动啦-社招的情况也不容乐观,除了之前的一大波裁员新闻,现在更多的是收紧HC,做人才盘点,各个厂的HC不会像以前那么多了.我在Githu ...

  3. [静态时序分析简明教程(三)]备战秋招,如何看懂一个陌生的timing report

    备战秋招,如何看懂一个陌生的timing report 一.写在前面 1.1 快速导航链接· 二.Timing Report 2.1 起始点与终止点 2.2 路径时钟域的归属 2.2 建立时间检查与保 ...

  4. 研二非科班研究生如何备战秋招

    持续坚持原创输出,点击蓝字关注我吧 作者:软件质量保障 知乎:https://www.zhihu.com/people/iloverain1024 ​最近知乎收到了一位研二非科班同学的付费咨询,让我帮 ...

  5. 如何备战秋招,找到满意的工作(转B站狂神)

    1.何为秋招? 1.1.应届生 暑假:大学生(实习.工作) 8月.春招! 应届毕业生! 2015年级 2019界 2016年级 2020界 应届毕业生: 大三升大四! 大三暑假找工作找实习! 大四:毕 ...

  6. 【秋招备战计划第一弹】今天就开始备战秋招

    写在最前面吧 这是一个纯 从自身经历和能力出发的个人分析案列 不具备普适性 个人标签 大三 - 2022届 - 双非本科 - Java后端开发 思维导图 上了 牛客热榜 蛮不错的 已经过去的春招 简单 ...

  7. 【备战秋招】每日一题:4月23日美团春招第三题:题面+题目思路 + C++/python/js/Go/java带注释

    为了更好的阅读体检,为了更好的阅读体检,,可以查看我的算法学习博客第三题-农村大亨 在线评测链接:P1247 题目内容 塔子哥是一个喜欢种田类的游戏的人,他觉得这样的游戏可以让他体验到农民的乐趣,同时 ...

  8. 有三AI 1000问回归,备战秋招,更多,更快,更好,等你来战!

    文/编辑 | 言有三 最近遇到了很多朋友来询问<有三AI 1000问>在哪里?本来我做这个专栏的初衷只是想提醒大家要多主动思考,多注意细节,没想到击中了很多同学的痛点,不过之前已经停更了. ...

  9. 【备战秋招】每日一题:2022年清华大学(深圳)保研夏令营机试题-第一题-树上计数

    为了更好的阅读体检,可以查看我的算法学习博客树上计数 题目内容 给一棵 N N N 个点的有根树,所有点从 1 1 1 到 N N N 标号,且以 1 1 1 号点为根.问树上有多少个点满足其子树内( ...

最新文章

  1. 华为,你终于活成了他们害怕的样子
  2. Python学习--最完整的基础知识大全
  3. 新入职一家公司如何梳理业务?
  4. django-一对一关系
  5. 客户端软件 大华_大华“飞燕”,一款主打稳定WiFi的路由器!
  6. flash播放器代码
  7. python爬取某人所有微博_python爬取微博用户关注和粉丝的公开基本信息
  8. 百度竞价恶意点击真的存在吗?
  9. 用c语言编写九九乘法表
  10. IDEA中文字体格式
  11. python和c++同时订阅两个话题,在一个回调函数中处理
  12. 如何查看 /dev/sda 下的文件
  13. 如何检查后台服务(Android的Service类)是否正在运行?
  14. Linux安装配置Discuz论坛(centos7)
  15. sudo漏洞修复升级
  16. 攻防世界 web高手进阶区 favorite_number
  17. C语言编程练习:用pow()函数实现求x的y次方的值
  18. 研发新员工培训流程(待续)
  19. 这套人工智能算法书已经出版了3卷,其中卷3深度学习和神经网络最受程序员喜欢
  20. 行业认证标准:AUTOSAR(汽车开放系统架构)开发了用于现代C++软件开发的标准AUTOSAR C++14

热门文章

  1. 职教云python程序设计答案_智慧职教云课堂APPPython程序设计考试期末考试答案
  2. 2020年下半年系统集成项目管理工程师上午试题解析(四)
  3. c语言怎么学自学,怎么学自学C语言啊?
  4. c# 创建excel表头及内容
  5. win11如何安装apk安卓应用?
  6. 网络流_最小割_洛谷P1345
  7. iOS 保存图片和视频
  8. 有个秋招拿到阿里offer的学生分享了整个面试流程
  9. 【pgsql存储过程导致的死锁】
  10. Adblock Plus | 世界排名第一的免费广告拦截程序