Java面试重点总结

1、关于设计模式

设计模式六大原则。
1、开闭原则:对扩展开发,对修改关闭
2、依赖倒置原则:面向接口编程,依赖于抽象而不依赖于具体
3、里氏替换原则:使用基类的地方都可以用其子类完美替换
4、接口隔离原则:一个接口只定义做一件事,降低耦合
5、迪米特法则:一个对象应当对其他对象有尽可能少地了解
6、单一职责原则:类的功能要简单明确,不能包罗万象

简述一下你了解的设计模式。
设计模式,就是对反复使用的代码做的设计经验总结,分为三类创建型、结构型、行为型共 23 种设计模式,常用的有以下

  • 单例模式:单例模式三要素
    a)私有构造方法;
    b)私有静态引用;
    c)公有静态方法
    单例模式又分为线程安全的饿汉式和线程不安全的懒汉式,饿汉式是类加载进来就创建好了实例对象,懒汉式是用到这个对象时再创建。
  • 工厂模式:工厂抽象类可以根据条件生成不同的子工厂实现类对象,这些子工厂实现类重写了工厂抽象类的抽象方法用于生产产品对象。
    在这里插入图片描述
  • 代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。实际开发中,如果需要扩展需求,根据开闭原则不建议修改实现类代码,这时用代理类就方便很多。代理模式又分为静态代理和动态代理。静态代理是在编译期间就指定了代理对象。动态代理是在程序运行时通过反射机制动态创建生成。

2、关于事务的理解

事务ACID特性

原子性(Atomicity):事务中Sql语句不能再分,要么同时执行成功,要么同时执行失败.
一致性(Consistency):事务执行之前和执行之后,事务中数据的总状态不变.
隔离性(Isolation):事务与事务之间是彼此隔离,互不干扰的.
持久性(Durability):事务提交之后对数据库的更改将是永久.

事务隔离级别/机制:安全性越高,执行效率越低,安全性越低,执行效率越高.

读未提交: READ UNCOMMITTED 会导致脏读、不可重复读、虚读的发生。
读已提交: READ COMMITTED 会导致不可重复读、虚读的发生。
可重复度: REPEATABLE READ 会导致虚读的发生。
序列化: SERIALIZABLE 脏读、不可重复读、虚读都不发生。
注意:Oracle数据库默认采用READ COMMITTED隔离级别.
MySql数据库默认采用REPEATABLE READ 隔离级别.

事务隔离错误:在数据库的事务中不允许出现的现象.但是有的错误不影响Java程序.

脏读:一个线程中事务读取另一个线程中事务没有提交数据.(程序不允许)
不可重复读:一个线程中事务读到另一个线程中事务刚刚提交修改或删除的数据.
幻读(虚读):一个线程中事务读取另一个线程中事务刚刚提交的新增的数据.

3、关于集合

集合继承关系图如下:
在这里插入图片描述
上述类图中,实线边框的是实现类,比如ArrayList,LinkedList,HashMap等,折线边框的是抽象类,比如AbstractCollection,AbstractList,AbstractMap等,而点线边框的是接口,比如Collection,Iterator,List等。

  • Collection接口
    • List接口
      • ArrayList实现类
      • LinkedList实现类
      • Vector实现类
    • Set接口
      • HashSet实现类
      • LinkedHashSet实现类
      • TreeSet实现类
  • Map接口
    • HashMap实现类
    • LinkedHashMap实现类
    • TreeMap实现类
    • Hashtable实现类

集合框架底层数据结构:

  • Collection接口
    • List接口
      • ArrayList实现类 数组
      • LinkedList实现类 双向链表
      • Vector实现类 数组,就比Arraylist多了个 synchronized (线程安全)
    • Set接口
      • HashSet实现类 基于HashMap实现
      • LinkedHashSet实现类 继承HashSet,内部基于LinkedHashMap实现
      • TreeSet实现类 红黑树(红黑树是一种特殊的平衡二叉查找树)
  • Map接口
    • HashMap实现类 JDK1.8之前数组+链表,JDK1.8以后当链表长度超过8时转变为红黑树
    • LinkedHashMap实现类 集成自HashMap,在HashMap的基础上增加了一条双向链表实现了数据的有序
    • TreeMap实现类 红黑树
    • Hashtable实现类 和HashMap一样,就比hashMap多了个synchronized (线程安全)

List和Set的区别:
List有序(指的是元素存入集合的顺序和取出的顺序)、可重复、可存入多个null、常用的实现类有ArrayList,LinkedList,Vector等;
Set无序、不可重复、只能存一个null、常用的实现类有HashSet,LinkedHashSet,TreeSet。

关于Map:Map是以键值对的方式来存储数据,key无序且唯一,允许有一个键为null,值无序可重复,允许多个null,常见的Map实现类有HashMap、LinkedHashMap、TreeMap、HashTable。

关于迭代器Iterator:Collection接口继承了Iterator,为遍历集合而生。

遍历List的实现方式有哪些,遍历List的最佳实践是什么?
for循环 增强for循环(缺点不易操作数据)Iterator迭代器
RandomAccess 接口是用来标记 List 实现是否支持随机访问的 ArrayList底层是数组,支持按下标随机访问,所以用for循环效率高些,否则建议用迭代器或增强for循环。

如何实现数组和 List 之间的转换?
数组转List:Arrays.asList()
List转数组:List集合对象.toArrays()

总结ArrayList,LinkedList和Vector :
ArrayList:底层是动态数组,默认容量初始值是10,每次扩容会增加原来的1/2,因为有数组下标,随机访问效率(查找)比较高,时间复杂度是 O(1),但是删除和插入元素时涉及到元素的移动,效率比较低。
LinkedList:底层是双向链表,插入和删除操作只需要改变头尾指针的指向,效率较高,但是查询操作因为没有下标的概念,需要从头遍历查找元素,效率较低。占用空间也比ArrayList多,因为它不仅要存储数据,还要存储头尾指针。
Vector:和ArrayList使用方式是一样的,但它是所有的方法都是同步的,线程安全,所以性能就比ArrayList差,初始容量是10,每次扩容会增加原来的一倍。

Set集合如何保证数据是不可重复的?
集合中的对象都需要重写hashcode()和equals方法,先通过hashcode()方法比较hash值是否相等,如果不相等肯定是两个不同的对象,如果相等进一步比较equals方法,根据返回值进一步判断两个对象是否相等。

HashSet,LinkedHashSet,TreeSet实现原理:
HashSet:基于HashMap实现,数据存放在HashMap的键上,值统一存放的是present。底层基本都是调用HashMap实现的
LinkedHashSet:基于LinkedHashMap实现,LinkedHashMap继承HashMap。双向链表维护了插入顺序,所以取出顺序能和插入顺序保持一致。
TreeSet:底层是TreeMap,基于红黑树实现,存储的数据默认是自然排序按升序排列。

HashMap的实现原理:
概述:HashMap是通过键值对来存储数据的,键不能重复允许为null,值可重复允许有多个null。
数据结构:在JDK1.8之前是哈希表+链表的形式,链表为了解决hash冲突,但是数据量很多,链表会影响性能,在1.8以后当链表长度超过8时,转化成性能更优异的红黑树。
存储实现:1.利用key的哈希算法计算出存储数据的地址值,将数据写入。如果出现哈希冲突(不同的key哈希值相同),就把key-value存储到该地址后面的链表中,长度超过8时会转变为红黑树。

HashMap的扩容操作:
在JDK1.8中,默认容量初始值是16,如果添加的元素超过阀值0.75就会扩容数组,每次扩容都是原来的2倍。

HashMap 与 HashTable 有什么区别?
线程安全:HashMap线程不安全,效率高;HashTable线程安全,效率低
Null:HashMap键可为null,HashTable键不能为null
初始容量和扩充:HashMap初始容量16,每次扩充是原来的2倍,HashTable初始容量11,每次扩充是原来的2倍加1
数据结构:JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制
推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap(采用分段锁机制,使锁的粒度更精细了一些,并发性能更好) 替代

什么是TreeMap 简介
线程非同步的有序key-value集合,根据键的做自然排序,底层是红黑树实现的。

如何决定使用 HashMap 还是 TreeMap?
HashMap对插入、删除和查找元素效率都是比较高的。如果需要对一个有序的key集合进行遍历,TreeMap是更好的选择。

数组(Array)和集合(ArrayList)的区别
数组可以存储基本数据类型和引用数据类型
数组大小固定,集合大小自动扩展
数组内置方法没有集合丰富,集合使用起来更方便

comparable接口和comparator接口的区别?
comparable接口出自java.lang包,它有一个 compareTo(Object obj)方法用来排序
comparator接口出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用来排序
Comparator相对于Comparable来说更加的灵活,耦合度低。更适用对某个对象实现多种排序方式。

TreeMap 和 TreeSet 在排序时如何比较元素?Collections 工具类中的 sort()方法如何比较元素?
TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进行排序。
Collections 工具类的 sort 方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象要实现 Comparable 接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator 接口的子类型(需要重写 compare 方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java 中对函数式编程的支持)。

Arrays.sort()和Collections.sort()两个方法的排序算法实现
Arrays.sort()方法,基本类型数据使用快速排序法,引用数据类型使用归并排序。[装x式回答:如果数组长度大于等于286且连续性好的话,就用归并排序,如果大于等于286且连续性不好的话就用双轴快速排序。如果长度小于286且大于等于47的话就用双轴快速排序,如果长度小于47的话就用插入排序。]
Collections.sort()对引用数据类型进行排序,其内部采取的是归并排序。

HashMap和LinkedHashMap
LinkedHashMap 是HashMap的一个子类,通过双向链表实现存入顺序和取出顺序一致。

4、关于Spring、ioc、aop

什么是spring
是一个开源轻量级框架,简化Java开发。支持IOC容器,提供AOP实现。

Spring两大核心理念
IOC(控制反转,包括依赖注入Di):控制反转指的是创建对象不由开发者手动new出对象,而是通过Spring框架中的容器来负责创建。依赖注入是指对象在容器中创建好后,将实例对象注入属性值并分配给调用的地方。
AOP面向切面编程:处理非核心业务,例如异常、日志、权限拦截等使程序员专注于核心业务的开发,底层是通过动态代理实现的。在切点(需要写切面的方法叫切点)上下织入一些横切逻辑实现增强处理,增强处理又分为前置,后置,环绕,异常抛出,最终增强。

JDK动态代理和CGLIB动态代理的区别
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,重写其中的方法
在Spring中如果被代理类实现接口时,Spring就会用JDK的动态代理,没有实现接口时,Spring使用CGlib动态代理。

Spring优缺点
优:IOC容器让相互协作的组件保持松散的耦合,简化开发;
AOP实现非核心业务逻辑的开发,方便统一处理日志,异常,权限拦截等功能;
方便集成各种优秀的框架,shiro,mybatis,hibernate等;
降低了使用javaee api的难度,它对javaee开发中一些难用的api例如jdbc、远程调用等都提供了封装,降低了开发者的使用难度。
缺点:spring依赖反射,反射影响性能;使用门槛较高,入门spring需要较长时间。

Spring 框架中都用到了哪些设计模式?
单例模式:Bean默认为单例模式。
工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现-ApplicationListener。

依赖注入的实现方式有哪些?(给对象的属性赋值)
1.set方法注入,灵活性好
2.构造方法注入,时效性好
3.p命名注入
4.spel注入

用Spring容器获取对象的几种方式
通过bean的id获取
通过bean的name获取
通过工厂静态方法
通过实例静态方法

关于在属性上的注解@Autowired,@Qualifier(),@Resource
@Autowired:按照类型装配,给对象类型属性自动装配适合对象,前提这个对象的类型有一个,如果有多个就会报错。
@Qualifier() 当容器有多个同类型对象时,不知道装配那一个,通过此注解和@Autowired注解来指定装配对象。
@Resource 按照名称装配,是java的注释,但是Spring框架支持,@Resource指定注入哪个名称的对象@Resource(name=“name” type=“”) == @Autowired + @Qualifier(“name”)

关于在类上的注解@Component, @Controller, @Repository, @Service
@Component:将 java 类标记为 bean。意思是将该类的一个对象存放在容器中。
@Controller,@Service, @Repository 是标记特定的类的,这些注解分别标记在控制层逻辑层和数据层。方便开发者随时通过@Autowired注解从容器中获取对象使用。

spring bean的生命周期
1.Spring对bean进行实例化;
2.Spring将值和bean的引用注入到bean对应的属性中;
3.如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;
4.如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器5.实例传入;
5.如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
6.如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization()方法;
7.如果bean实现了InitializingBean接口,Spring将调用它们的after-PropertiesSet()方法。类似地,如果bean使用initmethod声明了初始化方法,该方法也会被调用;
8、如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization()方法;
9.此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
10.如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。

5、关于Springmvc,springboot

简介springmvc
Spring MVC是一个基于Java的实现了MVC设计模式的轻量级Web框架,mvc指的是模型视图控制器,springmvc将web层职责进行解耦,简化开发,提升开发效率。

springmvc工作原理
用户通过浏览器发送请求到springMvc前端控制器,然后由处理器映射器(handlermapper)根据url交由handler处理器来处理,然后就是逻辑业务层,持久层来处理逻辑和数据,将数据原路返回给处理器适配器(HandlerAdapter) 通过modelandview交还给前端控制器来处理,经过视图解析器解析后将嵌入数据的html页面返回给用户。

Spring MVC常用的注解有哪些?
@Conntroller:控制器的注解,专用于controller类上
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。
@ResponseBody:注解实现将数据转化为json对象响应给客户。
@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。

springboot的核心注解是哪个?它主要由哪几个注解组成的?
启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:
@SpringBootConfiguration实现配置文件的功能。
@EnableAutoConfiguration打开自动配置的功能。
@ComponentScan:Spring组件扫描。

拦截器和过滤器区别
在这里插入图片描述

比较一下 Spring Security 和 Shiro 各自的优缺点 ?
Spring Security 是一个重量级的安全管理框架;Shiro 则是一个轻量级的安全管理框架
Spring Security 概念复杂,配置繁琐;Shiro 概念简单、配置简单
Spring Security 功能强大;Shiro 功能简单

6、关于io

关于BIO、NIO、AIO、Netty
BIO:同步阻塞;NIO:同步非阻塞;AIO:异步非阻塞;其实IO主要分为BIO和NIO,AIO只是附加品,解决IO不能异步的实现;Netty是JBOSS提供的一个Java开源框架,由NIO演进而来,因为NIO编程非常繁重,Netty相当简化和流线化了网络应用开发过程。

BIO、NIO、AIO的区别
BIO:同步阻塞;NIO:同步非阻塞;AIO:异步非阻塞
BIO面向流的只能单向读写;NIO是面向缓冲的, 可以双向读写

io流的分类
按流的方向有输入输出流;按单位有字节流字符流;按角色有节点流和处理流
1、输入流:从文件读到内存;输出流:从内存读到文件
2、字节流以byte数组处理数据,像图片文件音乐视频的等
字符流一般以char数组接收数据,一般来处理字符类型的数据
3、节点流:直接与数据源(文件)相连,读入或读出。
处理流:对已存在流的连接进行封装,对数据进行缓存能更高效的读取文件。

什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作
对象序列化,将对象以二进制的形式保存在硬盘上(内存中的对象数据读出到硬盘)
反序列化;将二进制的文件转化为对象读取
实现serializable接口,不想某些字段放在硬盘上就加transient

在实现序列化接口是时候一般要生成一个serialVersionUID字段,它叫做什么,一般有什么用
如果用户没有自己声明一个serialVersionUID,接口会默认生成一个serialVersionUID。
建议用户自定义一个serialVersionUID(先进行序列化,然后在反序列化之前修改了类,那么就会报错。因为修改了类,对应的SerialversionUID也变化了,而序列化和反序列化就是通过对比其SerialversionUID来进行的,一旦SerialversionUID不匹配,反序列化就无法成功。)

IO的常用类和方法,以及如何使用
请添加图片描述

超类代表顶端的父类(都是抽象类)

java.io.InputStream

java.io.OutputStream

java.io.Reader

java.io.Writer

7、关于jvm

关于编译执行和解释执行
编译执行:将源文件编译成字节码,一次编译多次执行/执行效率不高,不可跨平台
解释执行:将源文件一行一行解释,一行一行执行。不同操作系统具备不同解释器/执行效率低,可跨平台

java怎么实现跨平台的:将源文件编译成字节码文件(.class),再将字节码文件解释执行。不同平台提供了不同解释器,java根据不同解释器实现了跨平台。

JRE:JAVA运行环境(包含jvm和解释器)
JDK:JAVA开发工具包(包括JRE+类库)

jvm的组成:请添加图片描述
JVM包含两个子系统和两个组件: 两个子系统为Class loader(类装载子系统)、Execution engine(解释器执行引擎); 两个组件为Runtime data area运行时数据区(即内存)、本地接口和类库。

jvm运行流程/java执行机制:首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在内存的方法区内,再由解析器执行引擎(Execution Engine)将字节码翻译成机器识别的二进制指令,这个过程中需要调用本地库接口来支持整个程序的完整运行。

说一下 JVM 运行时数据区/说一下 JVM 内存模型
请添加图片描述
1、程序计数器:处理字节码指令,循环跳转计算异常处理等。
2、虚拟机栈:服务java方法的
3、本地方法栈:调用本地native方法的
4、java堆:java 虚拟机中内存最大的一块,是被所有线程共享的一块内存区域,几乎所有的对象实例都在这里分配内存
5、方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据

你能给我详细的介绍Java堆吗?(重点理解)
1、java堆(Java Heap)是java虚拟机所管理的内存中最大的一块,是被所有线程共享的一块内存区域,此内存区域的唯一目的就是存放对象实例。
2、在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。
3、java堆是垃圾收集器管理的主要区域,因此也被成为“GC堆”。
4、从内存回收角度来看java堆可分为:新生代和老生代。
5、从内存分配的角度看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区。
6、无论怎么划分,都与存放内容无关,无论哪个区域,存储的都是对象实例,进一步的划分都是为了更好的回收内存,或者更快的分配内存。
7、根据Java虚拟机规范的规定,java堆可以处于物理上不连续的内存空间中。当前主流的虚拟机都是可扩展的(通过 -Xmx 和 -Xms 控制)。如果堆中没有内存可以完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

深拷贝和浅拷贝
浅拷贝(shallowCopy)只是拷贝了引用
深拷贝(deepCopy)申请了一块新的内存空间用来存放拷贝的对象,然后新的引用指向这个对象

java既然有垃圾回收机制,为什么还会发生内存泄露?
长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露典型的发生场景。

垃圾回收器的原理是什么?有什么办法手动进行垃圾回收?
当一个对象被创建时,gc就开始监控这个对象,通常gc采用有向图的方式来管理堆中的对象,通过这种方式来确定哪些对象是可达哪些是不可达的,gc机制有责任回收那些不可达对象。程序员也可以手动执行System.gc,这只是告诉gc可以执行垃圾回收,但是java语言规范并不保证gc一定会执行。

JVM 中都有哪些引用类型?
强引用:发生 gc 的时候不会被回收。
软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。
弱引用:有用但不是必须的对象,在下一次GC时会被回收。
虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时返回一个通知。

怎么判断对象是否可以被回收?以及回收时用到的算法有哪些?
一般有两种方法来判断:引用计数法和可达性分析算法
引用计数法因为不能解决循环引用的问题现已被淘汰
可达性分析算法通过有向图来确定哪些对象是可达哪些是不可达的,gc机制有责任回收那些不可达对象。
jvm垃圾回收的算法:
1、标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。
2、复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。
3、标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
4、分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法。

常用的 JVM 调优的参数都有哪些?
-Xms:初始堆大小
-Xmx:最大堆大小

8、关于异常

在这里插入图片描述

运行时异常:RuntimeException类及它的子类都是运行时异常,在编译期不要求强制处理的异常,一般是指编程时的逻辑错误。(类型转换异常、数组下标越界异常、空指针异常)
编译时异常:必须处理的异常,捕获或抛出,否则编译不通过。

throw 和 throws 的区别是什么?
throws 是在方法上声明该方法要拋出的异常,可抛出多种异常; throw 是在方法内部拋出异常对象,只能抛出一种异常。

final、finally、finalize 有什么区别?
final可以修饰类、方法、变量,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量。
finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
finalize属于Object类的一个方法,而Object类是所有类的父类,Java 中允许使用 finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。0

9、TCP、UDP、Socket、HTTP网络编程

在这里插入图片描述

TCP与UDP区别
TCP是面向连接的协议,发送数据前要先建立连接,TCP提供可靠安全的数据传输服务;TCP通信类似于于要打个电话,接通了,确认身份后,才开始进行通行;TCP只支持点对点通信
UDP是无连接的协议,发送数据前不需要建立连接,是不可靠不安全的但是时效性比较好;UDP通信类似于学校广播,靠着广播播报直接进行通信;UDP支持一对一、一对多、多对一、多对多

tcp三次握手
客户端向服务端发送SYN
服务端返回SYN,ACK
客户端发送ACK
现实场景来面试(我投递简历;你看到我的简历通知我来面试;我来了)
tcp四次握手请添加图片描述
三次握手和四次握手分别是在传输数据前和传输数据后发生的。客户端第一次握手是对服务器说:我要关闭连接了;第二次握手是服务端回复消息说:好的,你要关闭连接了。;第三次握手是服务端确定没有什么数据要传输给客户端了,对客户端说:我要关闭连接了;第四次握手是客户端回复服务端说:行,关吧。

关于http协议:应用层的超文本传输协议
http请求的组成:请求行(url),请求头,请求正文
http响应的组成:状态行,响应头,响应正文

http和https的区别?
其实HTTPS就是从HTTP加上加密处理

一次完整的HTTP请求所经历几个步骤?
1、建立TCP连接(tcp三次握手)
2、Web浏览器向Web服务器发送请求行
3、Web浏览器向Web服务器发送请求头(之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。有请求正文的再发送正文数据)
4、Web服务器应答,反馈响应的状态码
5、Web服务器发送应答头
6、Web服务器向浏览器发送数据
7、web服务器关闭tcp连接(tcp四次握手)

Http协议中有那些请求方式
在这里插入图片描述
restful风格:其中,GET 用于查询资源,POST 用于创建资源,PUT 用于更新服务端的资源的全部信息,PATCH 用于更新服务端的资源的部分信息,DELETE 用于删除服务端的资源。

GET方法与POST方法的区别
1、get重点在从服务器上获取资源,post重点在向服务器发送数据;
2、 Get传输的数据量小,因为受URL长度限制,但效率较高; Post可以传输大量数据,所以上传文件时只能用Post方式;
3、get是不安全的,因为get请求发送数据是在URL上,是可见的,可能会泄露私密信息,如密码等; post是放在请求体的,是安全的

什么是对称加密与非对称加密
对称密钥加密是指加密和解密使用同一个密钥的方式,这种方式存在的最大问题就是密钥发送问题,即如何安全地将密钥发给对方;
而非对称加密是指使用一对非对称密钥,即公钥和私钥,公钥可以随意发布,但私钥只有自己知道。发送密文的一方使用对方的公钥进行加密处理,对方接收到加密信息后,使用自己的私钥进行解密。
由于非对称加密的方式不需要发送用来解密的私钥,所以可以保证安全性;但是和对称加密比起来,非常的慢

cookie和session对于HTTP有什么用?
HTTP协议本身是无法判断用户身份。所以需要cookie或者session

什么是cookie,什么是session,以及他们的区别。
cookie是由Web服务器保存在用户浏览器上的文件(key-value格式),可以包含用户相关的信息。客户端向服务器发起请求,就提取浏览器中的用户信息由http发送给服务器
session是将用户信息保存在服务器中的,cookie中存的是 sessionid,服务器根据传输cookie 中的 sessionid 获取出会话中存储的信息,然后确定会话的身份信息。
区别:
1、cookie数据存放在客户端上,安全性较差,session数据放在服务器上,安全性相对更高
2、单个cookie保存的数据不能超过4K,session无此限制
3、session一定时间内保存在服务器上,当访问增多,服务器压力大,考虑到服务器性能方面,应当使用cookie。

10、并发编程

并行和并发有什么区别?
并发:多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。
并行:单位时间内,多个处理器或多核处理器同时处理多个任务,是真正意义上的“同时进行”。
串行:有n个任务,由一个线程按顺序执行。由于任务、方法都在一个线程执行所以不存在线程不安全情况,也就不存在临界区的问题。
并发 = 俩个人用一台电脑。
并行 = 俩个人分配了俩台电脑。
串行 = 俩个人排队使用一台电脑。

线程和进程区别
进程:cpu资源分配的基本单位,系统上运行的程序都是一个进程,一个进程里可能包括多个线程,一个进程挂掉后不会影响其他进程,但时一个线程挂掉后可能导致整个进程都崩溃。
线程:处理器任务调度和执行的基本单位,不同的线程共享进程分配来cpu时间片和资源,线程之间是竞争关系。

创建线程的四种方式
1、继承thread类
2、实runnable接口(无返回值
3、实现callable接口(有返回值
4、使用匿名内部类

线程的run()和start()有什么区别?
通过调用Thread的start方法来标志着线程处于就绪状态,等到抢到了cpu时间片的时候就会执行run方法中的具体代码,start方法里面就是调用的run方法,run可以重复调用而start只能调用一次。

线程的五种状态
1、新建状态:创建了一个线程对象
2、就绪状态:调用了start方法后就处于就绪状态
3、运行状态:就绪状态的线程抢到了cpu时间片,调用了run方法执行程序代码
4、阻塞状态:线程执行的wait方法;获取锁失败;调用了sleep,join方法都会使线程放弃对cpu的使用权,停止运行。阻塞状态不是每个线程必须要经历的状态
5、死亡状态:线程run()、main()方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。

请说出与线程同步以及线程调度相关的方法。
1、wait():wait() 是 Object类的方法,使一个线程处于阻塞状态,并且释放所持有的对象的锁;
2、sleep():sleep() 是 Thread线程类的静态方法,使一个正在运行的线程处于睡眠状态,调用此方法后属于阻塞状态,但是不会释放所持有的对象的锁。
3、notify():唤醒一个处于wait状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由 JVM 确定唤醒哪个线程,而且与优先级无关;
4、notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入运行状态;

关于yield
礼让线程,当一条线程执行到yield方法时,就会让出cpu时间片从运行状态到就绪状态,和其他就绪状态的线程一同竞争cpu时间片

如何停止一个正在运行的线程?
1、正常run方法结束后退出线程
2、使用stop方法终止线程,这个方法不推荐,是过期作废的方法
3、使用interrupt方法中断线程

线程同步的4种方式
线程同步是为了解决死索问题的
1、同步方法:synchronized
2、同步代码块:synchronized
3、使用重入锁:ReentrantLock
4、使用特殊域变量(volatile):保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

synchronized 和 Lock/ReentrantLock 有什么区别?
1、synchronized是关键字而Lock/ReentrantLock是个Java接口/类;
2、synchronized 可以给类、方法、代码块加锁;而 lock/ReentrantLock 只能给代码块加锁。
3、synchronized 不需要手动获取锁和释放锁,使用简单,发生异常会自动释放锁,不会造成死锁;而 lock 需要自己加锁和释放锁,如果使用不当没有 unLock()去释放锁就会造成死锁。

乐观锁和悲观锁的理解及如何实现,有哪些实现方式?
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。再比如 Java 里面的同步原语 synchronized 关键字的实现也是悲观锁。
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于多读的应用类型,这样可以提高吞吐量。在 Java的原子变量类就是使用了乐观锁的一种实现方式 CAS 实现的。
CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。   
CAS 操作要比较三个操作数 —— 需要读写的内存位置值、原值和新值。如果内存位置值与原值相匹配,那么说明此线程处理数据的时候没有其他线程对此数据做更改,处理器会自动将该位置值更新为新值。否则处理器不做任何操作。

在 Java 中 Executor 和 Executors 的区别?
Executors 工具类的不同方法按照我们的需求创建了不同的线程池,来满足业务的需求。
Executor 接口对象能执行我们的线程任务。

线程池种类?
1、可缓存的线程池:可随机创建线程对象,线程对象在1min内可以循环使用,如果1min内无任务执行,就会自动回收这个线程对象.
2、固定大小的线程池
3、创建只有一个线程对象的线程池

阻塞队列

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。JDK7 提供了 7 个阻塞队列。分别是:ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。DelayQueue:一个使用优先级队列实现的无界阻塞队列。SynchronousQueue:一个不存储元素的阻塞队列。LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。Java 5 之前实现同步存取时,可以使用普通的一个集合,然后在使用线程的协作和线程同步可以实现生产者,消费者模式,主要的技术就是用好,wait ,notify,notifyAll,sychronized 这些关键字。而在 java 5 之后,可以使用阻塞队列来实现,此方式大大简少了代码量,使得多线程编程更加容易,安全方面也有保障。BlockingQueue 接口是 Queue 的子接口,它的主要用途并不是作为容器,而是作为线程同步的的工具,因此他具有一个很明显的特性,当生产者线程试图向BlockingQueue 放入元素时,如果队列已满,则线程被阻塞,当消费者线程试图从中取出一个元素时,如果队列为空,则该线程会被阻塞,正是因为它所具有这个特性,所以在程序中多个线程交替向 BlockingQueue 中放入元素,取出元素,它可以很好的控制线程之间的通信。阻塞队列使用最经典的场景就是 socket 客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。

11、SpringCloud面试题

SpringCloud由什么组成?
这就有很多了,我讲几个开发中最重要的
Spring Cloud Eureka:服务注册与发现
Spring Cloud Zuul:服务网关
Spring Cloud Ribbon:客户端负载均衡
Spring Cloud Feign:声明性的Web服务客户端
Spring Cloud Hystrix:断路器
Spring Cloud Config:分布式统一配置管理
等20几个框架,开源一直在更新

Spring Cloud 和dubbo区别?
服务调用方式:dubbo是RPC springcloud Rest Api
注册中心:dubbo 是zookeeper springcloud是eureka,也可以是zookeeper
服务网关,dubbo本身没有实现,只能通过其他第三方技术整合,springcloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发,springcloud支持断路器,与git完美集成配置文件支持版本控制,事物总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素。

什么是eureka,服务注册与发现指的是什么
在微服务架构中,我们把一个大项目拆分成很多有着不同功能的微小服务,但是有时微小服务之间有着相互调用的关系,这时候我们就需要是知道被调用服务的ip和端口号,那么我们就需要一个环境来统一管理每一台服务器的ip和端口号,于是在Spring Cloud中就产生了Eureka注册中心来管理微服务信息。
什么是Eureka的自我保护模式:注册到Eureka上的服务会实时汇报自己的状态,一旦某一个服务崩了,eureka会根据实际问题来决定是否从服务队列中保护或剔除这个不可用服务.
Eureka服务的注册与发现,这句话我的理解就是ip和端口上传到eureka和从eureka把ip和端口下载下来。

什么是Spring Cloud Zuul(服务网关)
API网关根据请求的url,路由到相应的服务,然后将请求结果返回给用户。它不仅可以对请求做一个反向代理和负载均衡, 还能通过内置的过滤器进行请求的过滤或拦截,当请求一个服务器超时时,也能够对服务进行降级或熔断处理,防止服务因为压力过大造成雪崩。

Zuul与Nginx有什么区别?既然Nginx可以实现网关?为什么还需要使用Zuul框架
Zuul是SpringCloud集成的网关,使用Java语言编写,可以对SpringCloud架构提供更灵活的服务。Nginx是使用C语言实现,性能高于Zuul,但是实现自定义操作需要熟悉lua语言,对程序员要求较高。

关于Spring Cloud Ribbon和Spring Cloud Hystrix
zuul内置了ribbon,当客户端请求过来的时候会从eureka上拉取到服务可用列表,通过ribbon做一个负载均衡的转发。
zuul内置了Hystrix,可以对不可用的服务做一个降级或熔断处理,防止发生服务雪崩。

Hystrix解决雪崩的主要方式
服务降级:接口调用失败就调用本地的方法可以返回一个友好提示
服务熔断:接口调用失败就会进入调用接口提前定义好的一个熔断的方法,返回错误信息

负载均衡是怎么处理高并发是的?(nginx负载均衡和ribbon负载均衡的区别?)
用户请求先到达负载均衡器(nginx),负载均衡器根据负载均衡算法将请求反向代理到微服务。这是前后台交互的一个服务端负载均衡处理,那么在后端服务与服务之间的相互调用是通过客户端Ribbon负载均衡来实现的(feign封装了ribbon),它是在eureka上获取到服务列表,将服务列表缓存在jvm上,然后进行一个负载均衡的转发到不同的服务器上,从而可以为微服务集群分担请求,降低系统的压力。

Feign与Ribbon的比较
Feign封装了Ribbon,他们之间最大的区别就是Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。 Feign则是在Ribbon的基础上进行了一次改进,采用接口的方式,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建http请求。不过要注意的是抽象方法的注解、方法签名要和提供服务的方法完全一致。

正向代理和反向代理的学习
原文在这里,写的很好呦!

spring cloud config能解决的问题
随着项目规模的日益庞大,每个单独的服务器的配置文件随着不断地项目升级内容而不断增多,会引起一系列的更新和重启,运维苦不堪言也容易出错。所以就想到有没有一个办法能够统一管理所有项目的配置文件.

12、关于Redis

什么是redis?
Redis 是一个使用 C 语言写成的,开源的高性能key-value非关系缓存数据库。它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。(5种)

redis优缺点
优点:
读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
支持数据持久化,支持AOF和RDB两种持久化方式。
支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。
支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
缺点:
数据库容量受到物理内存的限制
Redis 不具备自动容错和恢复功能
Redis 较难支持在线扩容

Redis 的持久化机制是什么?各自的优缺点?
Redis 提供两种持久化机制 RDB(默认) 和 AOF 机制
rdb:按照一定的时间将内存的数据以快照的形式保存到硬盘中
aof:将Redis执行的每次操作命令记录到aof 文件中一次
rdb更快,aof更安全

Redis的过期键的删除策略
过期策略通常有以下三种:
定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。
惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。
定期过期:每隔一定的时间,会扫描一定数量设置过期时间的key,并清除其中已过期的key。

Redis的内存淘汰策略
全局的有:1、移除最近最少使用的key 2、随机移除
设置过期键的:1、为key创建一个定时器,到过期时间就会立即清除 2、只有当访问一个key时,才会判断该key是否已过期,过期则清除。3、每隔一定的时间,会扫描一定数量设置过期时间的key,并清除其中已过期的key。

什么是缓存击穿和缓存雪崩
就是用户请求透过redis去请求数据库服务器,导致数据库压力过载。
从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
就是redis服务由于负载过大而宕机然后导致数据库的负载过大也宕机,最终整个系统瘫痪
数据不要设置相同的生存时间,不然过期时,redis压力会大或者搭建redis集群

一致性问题
强一致性:这种一致性级别是最符合用户直觉的,它要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响大
弱一致性:这种一致性级别约束了系统在写入成功后,不承诺立即可以读到写入的值,也不承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态
最终一致性:最终一致性是弱一致性的一个特例,系统会保证在一定时间内,能够达到一个数据一致的状态。这里之所以将最终一致性单独提出来,是因为它是弱一致性中非常推崇的一种一致性模型,也是业界在大型分布式系统的数据一致性上比较推崇的模型
先操作Redis的数据,再操作数据库的数据
先操作数据库的数据,再操作Redis的数据
如论选择哪种方法,最理想的情况下,两个操作要么同时成功,要么同时失败,否则就会出现Redis和数据库数据不一致的情况。
遗憾的是,目前没有什么框架能够保证Redis的数据和数据库的数据的完全一致性。我们只能根据应用场景来采取一定的措施降低数据不一致出现的概率,在一致性和性能之间取得一个折中。
操作redis可以是更新redis或者是删除redis,如果是更新redis在多线程的情况下容易导致数据不一致,而且频繁的写操作意味着也要频繁的更改redis里对应的数据,redis服务压力较大。
那么只剩下删除redis,有两种选择,先更新数据库再删除redis,或者先删除redis再更新数据库
第一种先更新数据库再删除缓存可能存在两种异常情况:
1、更新数据库失败,这时可以通过程序捕获异常,直接返回结果,不再继续删除缓存,所以不会出现数据不一致的问题
2、更新数据库成功,删除缓存失败。导致数据库是最新数据,缓存中的是旧数据,数据不一致
针对情况2我们有两种解决方式,1是失败重试,将需要删除的key发送到消息队列,创建一个消费端,尝试删除这个key,直到删除成功为止,但是这种引进了消息队列,对业务代码造成了入侵,增加了系统不确定性;第二种解决方式是异步更新缓存,启动一个监听数据库日志的服务,因为写操作会更新binlog日志,然后在客户端完成对key的删除,删除失败再发送到消息队列中。
先删缓存再更新数据库
删除缓存失败,这时可以通过程序捕获异常,直接返回结果,不再继续更新数据库,所以不会出现数据不一致的问题
删除缓存成功,更新数据库失败。在多线程下可能会出现数据不一致的问题,这种情况可以采用延时双删策略,就是更新数据库数据以后再删除一次缓存.

redis集群
1、主从模式:一主多从,主机负责读写,从机一般只负责读,从机第一次进行数据同步的时候是全量同步,后续通过offset可进行增量复制数据。
哨兵模式:主从模式中当主机挂了,会选举一个从机当主机,可选举节点的优先级最高的,或者offset最大的因为数据最完整,或者是runid最小启动时间最早的。
cluster集群:通过hash进行数据分片,就是多个redis节点均分存储一定的数据,为了保证数据的高可用cluster集群也可以有主从模式和哨兵模式。

13、关于Nginx

是一个轻量级的负载均衡、反向代理的Web服务器,他可以处理2-3万并发连接数,官方监测能支持5万并发。

Nginx负载均衡的算法有哪些?
1、默认轮循
2、根据权重
3、ip绑定
4、url-hash根据url的hash结果来分配指定服务器。

Nginx配置高可用性怎么配置?
当上游服务器(真实访问服务器),一旦出现故障或者是没有及时相应的话,应该直接轮训到下一台服务器,保证服务器的高可用

nginx集群
需要用到第三方软件keepalived,当我们向服务端发起请求的时候,用的地址并不是我们配置的两台Nginx服务器的IP地址,而是我们设置的虚拟IP地址,而两台Nginx服务器的地址则称为我们的工作IP,当主Nginx服务器挂了之后,当我们再次访问的时候,实际上就是访问我们的从Nginx服务器来做具体的负载均衡了,具体提供服务的IP地址也从主Nginx服务器的IP切换到了从Nginx服务器的Ip,整个IP切换的过程对于用户来说是无感知的,其实有点类似于我们经常说的主从数据库。
然后整个工作IP地址变化的过程,业界起了一个特cool的名字,叫IP漂移。

14、关于MyBatis

是一个半自动化orm框架,内部封装了jdbc,开发时只关注sql,不需要花费精力加载驱动创建连接等繁杂过程,采用xml配置或注解来操作数据库数据,将结果集直接映射成pojo类,避免了几乎所有的jdbc代码和手动设置参数以及获取结果集。

Hibernate 和 MyBatis 的区别
相同点:都是基于jdbc的封装,是持久层框架,用于dao层开发
不同点:MyBatis 是java对象与sql语句执行结果的对应关系,多表关联配置简单,是一个半自动化持久层框架
Hibernate 是java对象与数据库表的对应关系,多表关联配置复杂,是一个全自动的、完全面向对象的持久层框架。

#{}和KaTeX parse error: Expected 'EOF', got '#' at position 7: {}的区别 #̲{}是占位符相当于?,能预编译…{}是拼接符,字符串替换,没有预编译处理。

MyBatis动态Sql:,,,,,

MyBatis的关联映射:就是在操作数据的时候把与之相关的顺带查出来
有三类:主键映射: 插入一条数据时把主键查出来
对象映射:在查询当前对象时顺带把与当前对象相关属性对象查询出来.
集合映射:在查询当前对象时顺带把与当前对象相关属性对象的集合查询出来

MyBatis的一二级缓存
默认开启一级缓存是sqlsession范围,如果第二次查询的sql和参数和第一次一样,且中间没有进行更改删除的操作就会将缓存里的数据返回,不用去请求数据库。二级缓存的作用域比较大是整个mapper范围,使用二级缓存属性类需要实现Serializable序列化接口。

15、关于linux

Unix和Linux有什么区别?
1、开源性:linux开源;unix是一款商业软件,需要付费授权使用
2、跨平台性:Linux操作系统具有良好的跨平台性能,要比unix好很多
3、可视化界面:Linux除了进行命令行操作,还有窗体管理系统;Unix只是命令行下的系统。
4、硬件环境:Linux操作系统对硬件的要求较低,安装方法更易掌握;Unix对硬件要求比较苛刻,按照难度较大。
5、用户群体:Linux的用户群体很广泛,个人和企业均可使用;Unix的用户群体比较窄,多是安全性要求高的大型企业使用,如银行、电信部门等,或者Unix硬件厂商使用,如Sun等。

linux常用命令:
cd:切换目录
pwd:显示当前目录的绝对路径
ls:列出当前目录下的文件或者目录,ll比ls更详细,有时间是否可读写等信息
touch :创建文件
mkdir :创建目录
cat :查看文件命令;Ctrl + d ;退出查看文件命令
cp:复制功能
mv:移动功能
rm:删除功能
vi/vim:编辑文件

16、关于ElasticSearch

介绍:是一个基于Lucene的高扩展的分布式搜索服务器,支持开箱即用。他的逻辑结构是一个倒排索引表。在使用前需要创建索引库:相当于创建数据库表;创建映射:相当于创建数据库表的字段;创建文档:相当于表中每一条记录,然后在添加文档的时候进行分词索引,搜索时拿关键字去匹配词,最终找到词关联的文档。

16、关于RabbitMQ

概念
消息从发送者到接收者的方式有两种:一种我们可以称为即时消息通讯,也就是说消息从一端发出后立即就可以达到另一端;另一种方式称为延迟消息通讯,即消息从某一端发出后,首先进入一个容器进行临时存储,当达到某种条件后,再由这个容器发送给另一端。 这个容器的一种具体实现就是消息队列

应用场景
异步处理,应用解耦,流量削锋和日志处理四个场景。

举例说明这四种应用场景
1、异步处理:用户注册后,需要发注册邮件和注册短信。传统的做法有两种1.串行的方式;2.并行方式。串行是指这三个任务由一条线程一次执行,加入每个任务需要50ms,那么就需要150ms,如果用并行的方式,用户注册以后,发注册邮箱和注册短信同时进行的话也需要100ms,第三种方式可以通过消息队列,用户注册以后,发送注册邮箱和注册短信的任务写入消息队列,随即就返回一个注册成功待激活的消息给用户,因为写入消息队列的时间会很短可以忽略不计,这种方式仅需要50ms,比串行速度提高了三倍,比并行提高了二倍。
2、应用解耦:订单与库存的业务
3、流量削锋:一般在秒杀或团抢活动中使用广泛。
4、日志处理:在大数据中负责日志数据采集,定时写入队列,大数据常用kafka做消息队列

RabbitMQ工作模式
1、工作队列模式:多个消费端共同消费同一个队列中的消息。
请添加图片描述

2、发布订阅模式:交换机将相同数据分发给不同队列,每个消费者监听自己的队列。
请添加图片描述
3、Routing路由模式
交换机根据routingkey来转发消息到指定的队列,每个消费者监听自己的队列,并且设置routingkey。
请添加图片描述
4、opics统配符模式(最常用)请添加图片描述
交换机根据通配符来转发消息到指定的队列,每个消费者监听指定的队列

.消息Ack确认机制
确认种类一般有生产端到交换机的确认,交换机到队列的确认,队列到消费端的确认。但一般常说的是队列到消费端的确认,消费端消息确认模式有:
AcknowledgeMode.NONE:自动确认
AcknowledgeMode.AUTO:根据情况确认
AcknowledgeMode.MANUAL:手动确认
手动确认可以在业务失败后进行一些操作,如果消息未被 ACK 则会发送到下一个消费者等操作,默认情况下消息消费者是自动 ack (确认)消息的。

消息延迟队列(订单超时关闭:在支付场景中,一般上订单在创建后30分钟或1小时内未支付的,会自动取消订单。)
RabbitMQ 本身没有直接支持延迟队列的功能,但是可以通过过期时间TTL和死信队列来模拟延迟队列。

什么是Spring Cloud Bus
Spring Cloud Bus集成了市面上常见的RabbitMQ和Kafka等消息代理。其会连接微服务系统中所有拥有Bus总线机制的节点,当有数据变更的时候,会通过消息中间件使用消息广播的方式通知所有的微服务节点同步更新数据。(如:微服务配置更新等)

17、关于java操作excel

Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到KB级别,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便

java大批量读写excel数据该怎么实现
读大批量excel数据可以使用分段缓存,需要使用Excel Streaming Reader第三方工具,它会把一部分的行(可以设置)缓存到内存中,在迭代时不断加载行到内存中,而不是一次性的加载所有记录到内存,这样就可以不断的读取excel内容并且不影响内存的使用。或者是使用poi的sax模式,但是sax模式过于复杂不太推荐使用。
写大批量excel数据
SXSSFWorkbook类,它使用的方式是采用硬盘空间来大幅降低堆内存的占用,在系统的临时文件夹目录创建一个临时文件,然后将所有大于约定行数的数据都存入临时文件,而不是全部放在内存中,内存中只存放最新的的约定条数的数据,从而实现以硬盘空间换取内存空间,避免内存溢出。
使用方式上与正常的Excel导出方法没有区别,只是将实例化的类换为SXSSFWorkbook

17、关于Docker和k8s

二者关系: Docker 和 k8s 相互依存。 Docker 是一个容器化平台,而 k8s 是 Docker 等容器平台的协调器。在业务发展初期只有几个微服务,用 Docker 就足够了,但随着业务规模逐渐扩大,容器越来越多,运维人员的工作越来越复杂,这个时候就需要编排系统协调管理和调度这些容器。

18、优化

1、关于建索引提升性能
索引就像一本书的目录,通过目录很容易查找到想要的具体内容。索引虽然会大大提升我们的检索效率,但也要创建和维护索引结构,当对表中数据做增删改的同时也要动态的维护索引目录;索引也是要占用物理空间的,以空间换时间。
一般需要建立索引的字段是跟在where orderby joinon后面的字段,它们要根据筛选条件进行全表扫描。
索引覆盖:如果要查询的字段都建立过索引,那么引擎会直接在索引表中查询而不会访问原始数据,因此我们需要尽可能的在select后只写必要的查询字段,以增加索引覆盖的几率。
2、索引类型
(1)主键索引:不可为null,不可重复,只能建立一个主键索引。
(2)唯一索引:可为null,不可重复,可建立多个唯一索引
(3)普通索引:没啥限制
(4)全文索引
3、创建索引的原则
(1)较频繁作为查询条件的字段才去创建索引
(2)更新频繁字段不适合创建索引
(3)尽量在不出现重复数据的列上建索引
4、优化
从sql层面,可以建索引一般是在where orderby joinon后面的字段建索引、查询时指定列名,要避免多余的查询字段,尽量命中索引;对于长难的查询语句可以考虑分解查询,或者适当的使用关联映射代替子查询;要避免is null这样的判断,避免用or,or可以用unionall代替,能用between就不要用in或者notin了这些都会放弃索引而进行全表扫描;
从数据库层面。最直观的体现就是表结构设计,字段的数据类型是否合适,建立合适的索引,表的字段不要太多,使用频率较低的字段可以分离行成新表;当表中数据量过大时,可以考虑使用缓存redis,或者部署数据库集群使读写分离,主库负责写,从库负责读;还有就是分库分表进行优化,主要有垂直分表和水平分表,垂直分表是把主键和一些列放在一个表中,把主键和其他列又组成新表,适用于某些列常用,某些列不常用的场景,这样的好处可以使得行数据变小,在查询时减少读取的行数,水平分区是表结构不变,通过某种策略将数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。

19、高并发相关

MySql并发问题
首先确定服务器性能,大多服务器是4核8g的,springboot项目内置的tomcat默认开启的线程是200,也就是说200个线程服务客户端发过来的请求,在考虑到接口的复杂程度,那么一秒大概能处理500到1000的并发,所以其实一般来说,当你的高并发压力来袭的时候,通常不会是数据库先扛不住了,而是你的业务系统所在机器抗不住了,比如你部署了2台机器,那么其实到每秒一两千并发的时候,这两台机器基本上cpu负载都得飙升到90%以上 ,压力很大
一次并发去请求接口,对于数据库来说可能就有多次请求连接,就会导致数据库有几千并发,对于4核8g的数据库服务器可能扛不住,所以常规化一点的公司的数据库生产环境是8核16的,能抗住大几千的并发,具体能抗多少并发也得看你数据库里的数据量 以及你的SQL语句的复杂度
在往上说

20、java基础知识易忘混淆知识点

1、面向对象的特征:封装,继承,多态;
多态又分为编译时多态和运行时多态,编译时多态指的是方法的重载,运行时多态指的是方法的重写.
2、给一个Integer类型赋值时,会调用 Integer 类的静态方法 valueOf,如果整型字面量的值在-128 到 127 之间,那么不会 new 新的 Integer对象,而是直接引用常量池中的 Integer 对象
3、关于switch
java1.5以前byte、short、int、char
java1.5以后枚举
java1.7以后String字符串
4、StringBuilder不安全
5、重载(Overload)和重写(Override)的区别
方法的重载和重写都是实现多态的方式
重载:同一个类中,方法名相同,参数列表不同,与返回值无关
重写:父类子类中,方法名,参数列表,返回值相同
6、抽象类(abstract class)和接口(interface)有什么异同?

  1. 抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。
  2. 接口比抽象类更加抽象,接口全是没有实现细节的代码,抽象类可以定义自己的方法
  3. 接口和抽象类的实现类都必须实现抽象方法,否则该类仍然是抽象类

7、如何实现对象克隆?
1). 实现 Cloneable 接口并重写 Object 类中的 clone()方法;
2). 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆.
8、

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Java面试宝典》是一本非常受欢迎的面试指南,主要针对Java软件开发岗位的面试准备提供帮助。该书涵盖了Java编程基础、多线程、集合框架、IO流、异常处理、JDBC、Web开发、大数据等多个方面的知识点。 这本书将面试中常见的问题进行了整理和分类,并提供了详细的答案解析。对于准备Java面试的求职者来说,这本书是一本非常有价值的工具书。通过系统地学习和掌握书中的内容,能够帮助求职者更全面、系统地准备面试,提高自己的面试竞争力。 《Java面试宝典》的特点是简明扼要、重点突出。该书对于每个知识点都进行了精简的讲解,突出了面试中经常被考察的核心知识点。同时,该书也提供了大量的面试实例和题目,使读者能够更好地理解和应用所学知识。 该书还特别关注了实际工作中的应用和技能要求,提供了一些面试技巧和经验。这些实用的内容可以帮助读者在面试中更好地展现自己的技术水平和解决问题的能力。 总之,《Java面试宝典》是一本非常有用的Java面试准备指南。通过学习和掌握该书中的内容,读者可以提高自己的面试技巧和竞争力,更好地应对Java软件开发岗位的面试挑战。 ### 回答2: 《Java面试宝典PDF》是一本关于Java面试题的电子书,主要针对Java开发者的面试准备而编写。这本书收集了大量经典的Java面试题,并给出了详细的答案解析,帮助读者理解和掌握这些问题的解决方法。 这本书的特点是内容丰富、系统全面。它从Java的基础知识开始,包括语法、面向对象编程、集合框架等,然后逐步深入到多线程、IO流、网络编程、数据库等更加复杂的主题。每个主题都有一系列相关的面试题,通过阅读和练习这些题目,读者可以加深对Java的理解和应用能力。 另外,这本书还涵盖了一些常见的面试技巧和策略。例如,在解答面试题时如何进行思考和组织答案,如何回答开放性问题和场景题,如何展示自己的项目经验等。这些技巧对于应聘者在面试过程中的表现非常重要,可以帮助他们更好地展现自己的实力和优势。 总的来说,《Java面试宝典PDF》是一本针对Java开发者的面试准备必备工具。它通过丰富的面试题目和答案解析,帮助读者提升Java知识水平和面试技巧,增加在面试中的竞争力。如果你正在准备Java面试,这本书将是你的理想选择。 ### 回答3: 《Java面试宝典PDF》是一本面向Java开发人员的面试备考资料。该书籍主要内容包括Java基础知识、常见的面试题、Java集合框架、多线程、IO流操作、网络编程、JVM原理等。 这本书从面试官的视角出发,系统地总结Java开发的面试题。通过阅读该书,可以对Java的相关知识点进行全面的复习和了解,为面试中的各种问题做好准备。 《Java面试宝典PDF》的特点有以下几点: 1. 全面而详细:该书囊括了Java开发过程中的各个方面,从基础知识到高级特性,从语言特性到框架应用,都有涉及。 2. 精选面试题:作者通过总结众多面试中的常见问题,并提供了详细的解答和分析,帮助读者更好地理解和应对类似问题。 3. 案例实践:书中提供了一些实际案例,通过这些案例,读者可以了解如何将Java知识应用到实际开发中,加深对Java编程的理解。 4. 简明扼要:尽管该书内容丰富,但作者在讲解问题的时候都力求简明扼要,注重重点和难点的阐述,方便读者快速掌握。 总之,《Java面试宝典PDF》是一本适合Java开发人员备考面试的好资料。通过阅读和学习,可以提高对Java技术的理解和掌握水平,增加面试成功的概率。但需要注意的是,该书只是辅助资料,实际面试还需要结合自身的实际经验进行准备和回答。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值