不懂就问系列,为什么别人能靠这份面试题宝典去大厂?(内附面试题答案)
就目前的一线企业面试模式来讲,尤其是一面与二面都涉及到很深的Java基础功底及知识面,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多朋友却苦于没有合适的复习资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。
我在网上搜集整理的这份Java面试核心笔记资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料,同时还分享一份我自己整理Java工程师高频面试文档,其中包括了包含集合,JVM,多线程并发、Spring,负载均衡,微服务,Redis,Dubbo,设计模式,数据结构,分布式等!【点击这里,暗号博客园】免费获取!
Java基础面试题
1. 何为编程
编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过
程。
为了使计算机能够理解人的意图,人类就必须要将需解决的问题的思路、方法、和手段通过计算机
能够理解的形式告诉计算机,使得计算机能够根据人的指令一步一步去工作,完成某种特定的任
务。这种人和计算机之间交流的过程就是编程。
2. 什么是Java
Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继
承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编
程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。
3. jdk1.5之后的三大版本
Java SE(J2SE,Java 2 Platform Standard Edition,标准版)
Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java
应用程序。Java SE 包含了支持 Java Web 服务开发的类,并为Java EE和Java ME提供基础。
Java EE(J2EE,Java 2 Platform Enterprise Edition,企业版)
Java EE 以前称为 J2EE。企业版本帮助开发和部署可移植、健壮、可伸缩且安全的服务器端Java 应
用程序。Java EE 是在 Java SE 的基础上构建的,它提供 Web 服务、组件模型、管理和通信 API,
可以用来实现企业级的面向服务体系结构(service-oriented architecture,SOA)和 Web2.0应
用程序。2018年2月,Eclipse 宣布正式将 JavaEE 更名为 JakartaEE
Java ME(J2ME,Java 2 Platform Micro Edition,微型版)
Java ME 以前称为 J2ME。Java ME 为在移动设备和嵌入式设备(比如手机、PDA、电视机顶盒和
打印机)上运行的应用程序提供一个健壮且灵活的环境。Java ME 包括灵活的用户界面、健壮的安
全模型、许多内置的网络协议以及对可以动态下载的连网和离线应用程序的丰富支持。基于 Java
ME 规范的应用程序只需编写一次,就可以用于许多设备,而且可以利用每个设备的本机功能。
4. Jdk和Jre和JVM的区别
看Java官方的图片,Jdk中包括了Jre,Jre中包括了JVM
JDK :Jdk还包括了一些Jre之外的东西 ,就是这些东西帮我们编译Java代码的, 还有就是监控Jvm
的一些工具 Java Development Kit是提供给Java开发人员使用的,其中包含了Java的开发工具,也
包括了JRE。所以安装了JDK,就无需再单独安装JRE了。其中的开发工具:编译工具(javac.exe),
打包工具(jar.exe)等
JRE :Jre大部分都是 C 和 C++ 语言编写的,他是我们在编译java时所需要的基础的类库 Java
Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。核心类库主要是java.lang
包:包含了运行Java程序必不可少的系统类,如基本数据类型、基本数学函数、字符串处理、线
程、异常处理类等,系统缺省加载这个包
如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。
Jvm:在倒数第二层 由他可以在(最后一层的)各种平台上运行 Java Virtual Machine是Java虚拟
机,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言可以实现跨平台。
5. 什么是跨平台性?原理是什么
所谓跨平台性,是指java语言编写的程序,一次编译后,可以在多个系统平台上运行。
实现原理:Java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟
机,该系统就可以运行java程序。
6. Java语言有哪些特点
简单易学(Java语言的语法与C语言和C++语言很接近)
面向对象(封装,继承,多态)
平台无关性(Java虚拟机实现平台无关性)
支持网络编程并且很方便(Java语言诞生本身就是为简化网络编程设计的)
支持多线程(多线程机制使应用程序在同一时间并行执行多项任)
健壮性(Java语言的强类型机制、异常处理、垃圾的自动收集等)
安全性好
7. 什么是字节码?采用字节码的最大好处是什么
字节码:Java源代码经过虚拟机编译器编译后产生的文件(即扩展为.class的文件),它不面向任
何特定的处理器,只面向虚拟机。
采用字节码的好处:
Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留
了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定
的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。
先看下java中的编译器和解释器:
Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟机器。这台虚拟的机
器在任何平台上都提供给编译程序一个的共同的接口。编译程序只需要面向虚拟机,生成虚拟机能
够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在Java中,这种供虚
拟机理解的代码叫做字节码(即扩展为.class的文件),它不面向任何特定的处理器,只面向虚拟
机。每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java源程序经过编译器编译后变
成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻
译成特定机器上的机器码,然后在特定的机器上运行,这就是上面提到的Java的特点的编译与解释
并存的解释。
Java源代码---->编译器---->jvm可执行的Java字节码(即虚拟指令)---->jvm---->jvm中解释器----->机
器可执行的二进制机器码---->程序运行。
8. 什么是Java程序的主类?应用程序和小程序的主类有何不同?
一个程序中可以有多个类,但只能有一个类是主类。在Java应用程序中,这个主类是指包含main()
方法的类。而在Java小程序中,这个主类是一个继承自系统类JApplet或Applet的子类。应用程序
的主类不一定要求是public类,但小程序的主类要求必须是public类。主类是Java程序执行的入口
点。
9. Java应用程序与小程序之间有那些差别?
简单说应用程序是从主线程启动(也就是main()方法)。applet小程序没有main方法,主要是嵌在浏
览器页面上运行(调用init()线程或者run()来启动),嵌入浏览器这点跟flash的小游戏类似。
10. Java和C++的区别
我知道很多人没学过C++,但是面试官就是没事喜欢拿咱们Java和C++比呀!没办法!!!就算没学过C++,也要
记下来!
都是面向对象的语言,都支持封装、继承和多态
Java不提供指针来直接访问内存,程序内存更加安全
Java的类是单继承的,C++支持多重继承;虽然Java的类不可以多继承,但是接口可以多继承。
Java有自动内存管理机制,不需要程序员手动释放无用内存
11. Oracle JDK 和 OpenJDK 的对比
- Oracle JDK版本将每三年发布一次,而OpenJDK版本每三个月发布一次;
- OpenJDK 是一个参考模型并且是完全开源的,而Oracle JDK是OpenJDK的一个实现,并不是完全
开源的; - Oracle JDK 比 OpenJDK 更稳定。OpenJDK和Oracle JDK的代码几乎相同,但Oracle JDK有更多的
类和一些错误修复。因此,如果您想开发企业/商业软件,我建议您选择Oracle JDK,因为它经过
了彻底的测试和稳定。某些情况下,有些人提到在使用OpenJDK 可能会遇到了许多应用程序崩溃
的问题,但是,只需切换到Oracle JDK就可以解决问题; - 在响应性和JVM性能方面,Oracle JDK与OpenJDK相比提供了更好的性能;
- Oracle JDK不会为即将发布的版本提供长期支持,用户每次都必须通过更新到最新版本获得支持来
获取最新版本; - Oracle JDK根据二进制代码许可协议获得许可,而OpenJDK根据GPL v2许可获得许可。
基础语法
数据类型
12. Java有哪些数据类型
定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同
大小的内存空间。
分类
基本数据类型
数值型
整数类型(byte,short,int,long)
浮点类型(float,double)
字符型(char)
布尔型(boolean)
引用数据类型
类(class)
接口(interface)
数组([])
JVM面试题
1.什么情况下会发生栈内存溢出。
思路: 描述栈定义,再描述为什么会溢出,再说明一下相关配置参数,OK的话可以给面试官手写是一
个栈溢出的demo。
我的答案:
栈是线程私有的,他的生命周期与线程相同,每个方法在执行的时候都会创建一个栈帧,用来存储
局部变量表,操作数栈,动态链接,方法出口等信息。局部变量表又包含基本数据类型,对象引用
类型
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常,方法递
归调用产生这种结果。
如果Java虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是无法申请到足够的内存去完成
扩展,或者在新建立线程的时候没有足够的内存去创建对应的虚拟机栈,那么Java虚拟机将抛出一
个OutOfMemory 异常。(线程启动过多)
参数 -Xss 去调整JVM栈的大小
2.详解JVM内存模型
思路: 给面试官画一下JVM内存模型图,并描述每个模块的定义,作用,以及可能会存在的问题,如栈
溢出等。
我的答案:JVM内存结构
程序计数器:当前线程所执行的字节码的行号指示器,用于记录正在执行的虚拟机字节指令地址,线程
私有。
Java虚拟栈:存放基本数据类型、对象的引用、方法出口等,线程私有。
Native方法栈:和虚拟栈相似,只不过它服务于Native方法,线程私有。
Java堆:java内存最大的一块,所有对象实例、数组都存放在java堆,GC回收的地方,线程共享。
方法区:存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码数据等。(即永久带),
回收目标主要是常量池的回收和类型的卸载,各线程共享
3.JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么
要分为Eden和Survivor。
思路: 先讲一下JAVA堆,新生代的划分,再谈谈它们之间的转化,相互之间一些参数的配置(如: –
XX:NewRatio,–XX:SurvivorRatio等),再解释为什么要这样划分,最好加一点自己的理解。
我的答案:
1)共享内存区划分
共享内存区 = 持久带 + 堆
持久带 = 方法区 + 其他
Java堆 = 老年代 + 新生代
新生代 = Eden + S0 + S1
2)一些参数的配置
默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ,可以通过参数 –XX:NewRatio 配
置。
默认的,Edem : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定)
Survivor区中的对象被复制次数为15(对应虚拟机参数 -XX:+MaxTenuringThreshold)
3)为什么要分为Eden和Survivor?为什么要设置两个Survivor区?
如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被
填满,触发Major GC.老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC
长得多,所以需要分为Eden和Survivor。
Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选
保证,只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代。
设置两个Survivor区最大的好处就是解决了碎片化,刚刚新建的对象在Eden中,经历一次Minor
GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;等Eden区再满
了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space
S1(这个过程非常重要,因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续
的内存空间,避免了碎片化的发生)
4. JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代
思路: 先描述一下Java堆内存划分,再解释Minor GC,Major GC,full GC,描述它们之间转化流程。
我的答案:
Java堆 = 老年代 + 新生代
新生代 = Eden + S0 + S1
当 Eden 区的空间满了, Java虚拟机会触发一次 Minor GC,以收集新生代的垃圾,存活下来的对
象,则会转移到 Survivor区。
大对象(需要大量连续内存空间的Java对象,如那种很长的字符串)直接进入老年态;
如果对象在Eden出生,并经过第一次Minor GC后仍然存活,并且被Survivor容纳的话,年龄设为
1,每熬过一次Minor GC,年龄+1,若年龄超过一定限制(15),则被晋升到老年态。即长期存
活的对象进入老年态。
老年代满了而无法容纳更多的对象,Minor GC 之后通常就会进行Full GC,Full GC 清理整个内存
堆 – 包括年轻代和年老代。
Major GC 发生在老年代的GC,清理老年区,经常会伴随至少一次Minor GC,比Minor GC慢10
倍以上。
5.你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。
思路: 一定要记住典型的垃圾收集器,尤其cms和G1,它们的原理与区别,涉及的垃圾回收算法。
我的答案:
1)几种垃圾收集器:
Serial收集器: 单线程的收集器,收集垃圾时,必须stop the world,使用复制算法。
ParNew收集器: Serial收集器的多线程版本,也需要stop the world,复制算法。
Parallel Scavenge收集器: 新生代收集器,复制算法的收集器,并发的多线程收集器,目标是达
到一个可控的吞吐量。如果虚拟机总共运行100分钟,其中垃圾花掉1分钟,吞吐量就是99%。
Serial Old收集器: 是Serial收集器的老年代版本,单线程收集器,使用标记整理算法。
Parallel Old收集器: 是Parallel Scavenge收集器的老年代版本,使用多线程,标记-整理算法。
CMS(Concurrent Mark Sweep) 收集器: 是一种以获得最短回收停顿时间为目标的收集器,标
记清除算法,运作过程:初始标记,并发标记,重新标记,并发清除,收集结束会产生大量空间碎
片。
G1收集器: 标记整理算法实现,运作流程主要包括以下:初始标记,并发标记,最终标记,筛选
标记。不会产生空间碎片,可以精确地控制停顿。
2)CMS收集器和G1收集器的区别:
CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用;
G1收集器收集范围是老年代和新生代,不需要结合其他收集器使用;
CMS收集器以最小的停顿时间为目标的收集器;
G1收集器可预测垃圾回收的停顿时间
CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片
G1收集器使用的是“标记-整理”算法,进行了空间整合,降低了内存空间碎片。
6.JVM内存模型的相关知识了解多少,比如重排序,内存屏障,
happen-before,主内存,工作内存。
思路: 先画出Java内存模型图,结合例子volatile ,说明什么是重排序,内存屏障,最好能给面试官写
以下demo说明。
我的答案:
1)Java内存模型图:
Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需 要自己的工作内存和主存之间进行数据同步进行。
2)指令重排序。
在这里,先看一段代码
运行结果可能为(1,0)、(0,1)或(1,1),也可能是(0,0)。因为,在实际运行时,代码指令可能并不是严格按
照代码语句顺序执行的。大多数现代微处理器都会采用将指令乱序执行(out-of-order execution,简
称OoOE或OOE)的方法,在条件允许的情况下,直接运行当前有能力立即执行的后续指令,避开获取
下一条指令所需数据时造成的等待3。通过乱序执行的技术,处理器可以大大提高执行效率。而这就是
指令重排。
3)内存屏障
内存屏障,也叫内存栅栏,是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。
LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的
数据被访问前,保证Load1要读取的数据被读取完毕。
StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行
前,保证Store1的写入操作对其它处理器可见。
LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出
前,保证Load1要读取的数据被读取完毕。
StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行
前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。 在大多数处理器的实
现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。
4)happen-before原则
单线程happen-before原则:在同一个线程中,书写在前面的操作happen-before后面的操作。
锁的happen-before原则:同一个锁的unlock操作happen-before此锁的lock操作。
volatile的happen-before原则:对一个volatile变量的写操作happen-before对此变量的任意操
作(当然也包括写操作了)。
happen-before的传递性原则:如果A操作 happen-before B操作,B操作happen-before C操
作,那么A操作happen-before C操作。
线程启动的happen-before原则:同一个线程的start方法happen-before此线程的其它方法。
线程中断的happen-before原则 :对线程interrupt方法的调用happen-before被中断线程的检测
到中断发送的代码。
线程终结的happen-before原则: 线程中的所有操作都happen-before线程的终止检测。
对象创建的happen-before原则: 一个对象的初始化完成先于他的finalize方法调用。
Netty面试题
最流行的 NIO 框架,由 JBOSS 提供的,整合了FTP,SMTP,HTTP协议
- API 简单
- 成熟稳定
- 社区活跃·
- 经过大规模验证(互联网、大数据、网络游戏、电信通信)
Elasticsearch、Hadoop 子项目 avro项目、阿里开源框架 Dubbo、使用 Netty
BIO
优点:模型简单,编码简单缺点:性能瓶颈,请求数和线程数 N:N 关系高并发情况下 ,CPU 切换线程上
下文损耗大案例:Tomcat 7之前,都是 BIO,7 之后是 NIO改进:伪 NIO,使用线程池去处理逻辑
IO 模式
同步阻塞:丢衣服->等洗衣机洗完->再去晾衣服同步非阻塞:丢衣服->去做其他事情,定时去看衣服是
否洗完->洗完后自己去晾衣服异步非阻塞:丢衣服-> 去做其他事情不管了,衣服洗好会自动晾好,并且
通知你晾好了
2. 五种 I/O 模型
五种 I/O 模型:阻塞 IO、非阻塞 IO、多路复用 IO、信号驱动 IO、异步 IO,前 4 种是同步 IO,在内核
数据 copy 到用户空间时是阻塞的
3. 阻塞 IO
4. 非阻塞 IO
5. IO 多路复用
核心:可以同时处理多个 connection,调用系统 select 和 recvfrom函数每一个socket 设置为 non- blocking 阻塞是被 select 这个函数 block 而不是 socket阻塞缺点:连接数不高的情况下,性能不一定 比 多线程+阻塞 IO 好(多调用一个select 函数)
信号驱动
异步 IO
采用 Future-Listener机制
IO 操作分为 2 步:
- 发起 IO 请求,等待数据准备
- 实际的 IO 操作,将数据从内核拷贝到进程中
阻塞 IO、非阻塞 IO 区别在于发起 IO 请求是否被阻塞
同步 IO、异步 IO 在于实际的 IO 读写是否阻塞请求进程
阻塞非阻塞是线程的状态
同步和异步是消息的通知机制
同步需要主动读写数据,异步不需要主动读写数据
同步 IO 和异步 IO 是针对用户应用程序和内核的交互
3.IO 多路复用
I/O 是指网络 I /O ,多路指多个 TCP 连接,复用指一个或几个线程。简单来说:就是使用一个或者几个
线程处理多个 TCP 连接,最大优势是减少系统开销,不必创建过多的线程进程,也不必维护这些线程进
程
select
文件描述符 writefds、readdfs、exceptfds30w个连接会阻塞住,等数据可读、可写、出异常、或者超
时返回select 函数正常返回后,通过遍历 fdset整个数组才能发现哪些句柄发生了事件,来找到就绪的
描述符fd,然后进行对应的 IO操作,几乎在所有的平台上支持,跨平台支持性好缺点: - select采用轮询的方式扫描文件描述符,全部扫描,随着文件描述符 FD 数量增多而性能下降。
- 每次调用 slect (),需要把 fd集合从用户态拷贝到内核态,并进行遍历(消息传递都是内核到用户
空间) - 最大缺陷就是单个进程打开的FD 有限制,默认是 1024
poll
基本流程和 select差不多,处理多个描述符也是轮询,根据描述符的状态进行处理,一样需要把fd集合
从用户态拷贝到内核态,并进行遍历。区别是poll 没有最大文件描述符限制(使用链表方式存储fd)
epoll
没有描述符限制,用户态拷贝到内核态只需要一次使用事件通知,通过epoll_ctl注册fd,一旦该fd 就绪,
内核就采用callback机制激活对应的fd优点: - 没有fd限制,所支持的 FD 上限是操作系统的最大文件句柄数(65535),1G 内存大概支持 10W
句柄,支持百万连接的话,16G 内存就可以搞定 - 效率高,使用回调通知而不是轮询方式,不会随着 FD 数目增加效率下降
- 通过 callback 机制通知,内核和用户空间 mmap 同一块内存实现
缺点:
编程模型比 select / poll 复杂
linux内核核心函数 - epoll_create() 系统启动时,会向linux内核申请一个文件系统,b+树,返回epoll 对象,也是一个
fd - epoll_ctl() 操作epoll对象,在这个对象里面修改添加删除对应的链接fd,绑定一个callback函数
- epoll_wait() 判断并完成对应的 IO 操作
例子:100W 个连接,1W 个活跃,在 select ,poll,epoll中怎么样表现
select :不修改宏定义,需要 1000 个进程才能支持 100W 连接
poll:100W连接,遍历都响应不过来,还有空间的拷贝消耗大量的资源
epoll: 不用遍历fd,不用内核空间和用户空间数据的拷贝
如果 100W 个连接中,95W 活跃,则 poll 和 epoll差不多
4.Java的i/o - jdk1.4之前是采用同步阻塞模型(BIO)
大型服务一般采用 C/C++,因为可以直接操作系统提供的异步 IO(AIO) - jdk1.4之后推出NIO,支持非阻塞 IO,jdk1.7 升级推出 NIO2.0,提供了AIO 功能,支持文件和网络
套接字的异步 IO
5.Netty 线程模型和 Reactor 模式
Reactor模式(反应器设计模式),是一种基于事件驱动的设计模式,在事件驱动的应用中,将一个或
者多个客户的请求进行分离和调度。在事件驱动的应用中,同步地,有序地处理接受多个服务请求。属
于同步非阻塞 IO优点: - 响应快,不会因为单个同步而阻塞,虽然 reactor本身是同步的
- 编程相对简单,最大程度避免复杂的多线程以及同步问题,避免了多线程、进程切换开销
- 可扩展性,可以方便的通过 reactor实例个数充分利用 CPU 资源
缺点: - 相对复杂,不易于调试
- reactor模式需要系统底层的支持。比如java中的selector支持,操作系统select系统调用支持
Reactor 单线程模型 - 作为 NIO 服务器,接受客户端 TCP 连接,作为 NIO 客户端,向服务端发起 TCP 连接
- 服务端读请求数据并响应,客户端写请求并读取响应
场景:
对应小业务则适合,编码简单,对于高负载,高并发不合适。一个 NIO 线程处理太多请求,负载
很高,并且响应变慢,导致大量请求超时,万一线程挂了,则不可用
Reactor 多线程模型
一个 Acceptor线程,一组 NIO 线程,一般是使用自带线程池,包含一个任务队列和多个可用线程场
景:可满足大多数场景,当Acceptor需要做负责操作的时候,比如认证等耗时操作 ,在高并发情况下
也会有性能问题
Reactor 主从线程模型
Acceptor不在是一个线程,而是一组 NIO 线程,IO 线程也是一组 NIO 线程,这样就是 2 个线程池去处
理接入和处理 IO场景:满足目前大部分场景,也是 Netty推荐使用的线程模型BossGroup 处理连接的
WorkGroup 处理业务的
Netty 使用 NIO 而不是 AIO
在 linux系统上,AIO 的底层实现仍然使用 epoll,与 NIO 相同,因此在性能上没有明显的优势Netty 整
体架构是 reactor 模型,采用 epoll机制,IO 多路复用,同步非阻塞模型Netty是基于 Java NIO 类库实
现的异步通讯框架特点: 异步非阻塞,基于事件驱动,性能高,高可靠性,高可定制性。
6.Echo服务
回显服务,用于调试和检测的服务
MySQL面试题
1. 唯一索引比普通索引快吗, 为什么
唯一索引不一定比普通索引快, 还可能慢.
- 查询时, 在未使用 limit 1 的情况下, 在匹配到一条数据后, 唯一索引即返回, 普通索引会继续匹配
下一条数据, 发现不匹配后返回. 如此看来唯一索引少了一次匹配, 但实际上这个消耗微乎其微. - 更新时, 这个情况就比较复杂了. 普通索引将记录放到 change buffer 中语句就执行完毕了. 而对
唯一索引而言, 它必须要校验唯一性, 因此, 必须将数据页读入内存确定没有冲突, 然后才能继续操
作. 对于写多读少的情况, 普通索引利用 change buffer 有效减少了对磁盘的访问次数, 因此普通
索引性能要高于唯一索引.
2. MySQL由哪些部分组成, 分别用来做什么
Server
连接器: 管理连接, 权限验证.
分析器: 词法分析, 语法分析.
优化器: 执行计划生成, 索引的选择.
执行器: 操作存储引擎, 返回执行结果.
2. 存储引擎: 存储数据, 提供读写接口.
3. MySQL查询缓存有什么弊端, 应该什么情况下使用, 8.0
版本对查询缓存有什么变更.
查询缓存可能会失效非常频繁, 对于一个表, 只要有更新, 该表的全部查询缓存都会被清空. 因此对
于频繁更新的表来说, 查询缓存不一定能起到正面效果.
对于读远多于写的表可以考虑使用查询缓存.
8.0版本的查询缓存功能被删了 ( ̄. ̄).
4. MyISAM和InnoDB的区别有哪些**
InnoDB支持事务, MyISAM不支持.
InnoDB支持行级锁, MyISAM支持表级锁.
InnoDB支持多版本并发控制(MVVC), MyISAM不支持.
InnoDB支持外键, MyISAM不支持.
MyISAM支持全文索引, InnoDB部分版本不支持(但可以使用Sphinx插件)
5. MySQL怎么恢复半个月前的数据
通过整库备份+binlog进行恢复. 前提是要有定期整库备份且保存了binlog日志.
6. MySQL事务的隔离级别, 分别有什么特点
- 读未提交(RU): 一个事务还没提交时, 它做的变更就能被别的事务看到.
- 读提交(RC): 一个事务提交之后, 它做的变更才会被其他事务看到.
- 可重复读(RR): 一个事务执行过程中看到的数据, 总是跟这个事务在启动时看到的数据是一致的. 当
然在可重复读隔离级别下, 未提交变更对其他事务也是不可见的. - 串行化(S): 对于同一行记录, 读写都会加锁. 当出现读写锁冲突的时候, 后访问的事务必须等前一个
事务执行完成才能继续执行.
7. 做过哪些MySQL索引相关优化
尽量使用主键查询: 聚簇索引上存储了全部数据, 相比普通索引查询, 减少了回表的消耗.
MySQL5.6之后引入了索引下推优化, 通过适当的使用联合索引, 减少回表判断的消耗.
若频繁查询某一列数据, 可以考虑利用覆盖索引避免回表.
联合索引将高频字段放在最左边.
8. 简要说一下数据库范式
第一范式: 属性不可再分.
第二范式: 在一范式的基础上, 要求数据库表中的每个实例或行必须可以被惟一地区分. 通常需要为
表加上一个列, 以存储各个实例的惟一标识. 这个惟一属性列被称为主关键字或主键.
第三范式: 在二范式的基础上, 要求一个数据库表中不包含已在其它表中已包含的非主关键字信息.
所以第三范式具有如下特征:1). 每一列只有一个值. 2). 每一行都能区分. 3). 每一个表都不包含其
他表已经包含的非主关键字信息.
9. 一千万条数据的表, 如何分页查询
数据量过大的情况下, limit offset 分页会由于扫描数据太多而越往后查询越慢. 可以配合当前页最后
一条ID进行查询, SELECT * FROM T WHERE id > #{ID} LIMIT #{LIMIT} . 当然, 这种情况下ID必须
是有序的, 这也是有序ID的好处之一.
10. 订单表数据量越来越大导致查询缓慢, 如何处理
分库分表. 由于历史订单使用率并不高, 高频的可能只是近期订单, 因此, 将订单表按照时间进行拆分, 根
据数据量的大小考虑按月分表或按年分表. 订单ID最好包含时间(如根据雪花算法生成), 此时既能根据订
单ID直接获取到订单记录, 也能按照时间进行查询
为了不影响观看,本文只截取部分面试内容以及答案,需要的可以【点击这里,暗号博客园】获取~~