2022 6.22 java综合乱入复习整理

1.双亲委派模型:

 

BootStrapClassLoad, ExtClassLoader, AppClassLoader.

通过向上委派加载,向上递到最顶,然后父类加载不到,再自己尝试去加载。

 

 

 

 

为什么要使用双亲委派模型(使用双亲委派模型的好处):

1)主要为了安全性,避免用户自己编写的类动态替换一些java的核心类,比如String

2) 同时也为了避免类的重复加载,因为JVM区分不同的类,不仅仅是根据类名,还会根据是否由同一个类加载器去加载。相同的Class文件被不同的ClassLoader加载就是两个不同的类。

 

 

2.对aop的理解:采用面向对象的方式,对于诸如异常,日志之类的处理,就算采用了面向对象,这时候有多个类,但是这多个类中每个类都要去处理日志和异常,并且每个类的处理逻辑还差不多,这时候就存在冗余代码了,并且这种类型的冗余是没办法通过面向对象的方式再去解决的。因此通过采用切面的方式,将分散在多个类中的重复逻辑代码抽成切面,然后再通过诸如动态代理等方式对原方法进行增强,这样子就能减少代码的冗余。aop可以看成是面向对象的补充。

 

3. == 和 equals 的区别

==是运算比较符,equals是方法。

==:如果它比较的是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的【地址值】是否相等。

equals:(用来比较两个对象的内容是否相等) 如果是Object类的equals,那么方法实现用的也是==比较符,此时比较的是两个对象的地址值。不过,我们一般都会重写equals,比如String类的equals方法,比较的就是两个字符串的内容是否相同。

 

4.线程的生命周期(线程有哪些状态)

1)线程通常有五种状态:【创建】,【就绪】,【运行】,【阻塞】和【死亡状态】。

2)阻塞分为三种:

2-1)等待阻塞:运行线程的wait方法

2-2)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入"锁池"中

2-3)其他阻塞:运行的线程执行sleep方法或join方法,或发出了I/O请求,JVM会把该线程置为阻塞状态。

3)各个状态的说明:

新建状态(New):新创建了一个线程对象。

就绪状态(Runnable):线程对象创建后,其他线程调用了该线程对象的start方法。这时候该线程就变成了可运行状态,也就是就绪状态,等待获取CPU的使用权。(*线程拥有了执行的所有必要条件后,就进入就绪状态。)

运行状态(Running):就绪状态的线程获得了CPU的使用权,执行程序代码。

阻塞状态(Blocking):阻塞状态是因为线程由于某种原因(比如获取锁失败,等待I/O等等)放弃CPU的使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

死亡状态(Dead):线程执行完成了或者因为异常退出了run方法,该线程结束生命周期。

  

5.简述Redis事务的实现

1)首先,通过MULTI命令将执行该命令的客户端从非事务状态切换至事务状态,这个切换是通过在客户端状态的flags属性中的REDIS_MULTI标识来完成的。(事务开始)

2)之后,如果客户端发送一些 get, set 之类的命令,那么这时候由于客户端处于事务状态,因此这些命令不会马上被执行,而是会进入队列(FIFO, 先进先出)。(命令入队)

3)当一个处于事务状态的客户端向服务器发送EXEC时,这个命令将马上被服务器执行。服务器会遍历这个客户端的事务队列,执行队列中保存的所有命令,最后将执行命令所得的结果全部返回给客户端。(执行事务:事务在执行过程中不会被中断,当事务队列中的所有命令都被执行完毕之后,事务才会结束)

ACID的实现:

原子性:对于Redis中的事务功能来说,事务队列中的命令要么全部执行,要么全部不执行,因此Redis的事务是具有原子性的

一致性:Redis通过谨慎的错误检测和简单的设计来保证事务的一致性

隔离性:Redis使用单线程的方式来执行事务(以及事务队列中的命令),并且服务器保证,在执行事务期间不会对事务进行中断,因此Redis的事务总是以【串行】的方式运行的,并且事务也总是具有隔离性。

持久性:Redis的事务是通过简单地用队列包裹了一组Redis命令,Redis并没有为事务提供任何额外的持久化功能。所以Redis的持久性是由Redis所使用的持久化模式决定的:

3-1)当服务器在无持久化的内存模式下运作时,事务不具有持久性:一旦服务器停机,包括事务数据在内的所有服务器数据都将丢失。

3-2)RDB模式:不具有持久性

3-3)AOF模式并且appendfsync设置为always:这时程序总会在执行命令之后调用同步(sync)函数,将命令数据真正保存到磁盘里,因此这种配置下的事务是具有耐久性的

3-4)AOF模式并且appendfsync设置为everysec:这时程序会每秒同步一次命令数据到硬盘。因为停机可能恰好发生在等待同步的那一秒内,这可能会造成事务数据丢失,所以这种配置下的事务不具有持久性。

 

6.说说你在开发的时候怎么在SpringBoot的基础上做拓展的?

1)比较low但是很有效的做法:通过百度去找,先做出来,正确实现出来,事后有时间再去调试研究源码。

2)如果百度找不到:尝试研究源码。*

 

7.什么cglib动态代理?和jdk动态代理有什么区别?

 

8.SpringMVC工作流程:

用户发送请求到DispatcherServlet,然后DispatcherServlet调用HandlerMapping处理器映射器。

之后处理器映射器找到具体的处理器(可根据xml配置或者注解进行查找),生成处理器和处理器拦截器(如果有则生成)并返回给DispatcherServlet。

之后:。。。。

 

9.Spring中的事务是如何实现的?

1)Spring事务底层是基于数据库事务和aop机制的

2)首先,对使用了@Transactional注解的bean,Spring会创建一个代理对象作为bean

3)当调用代理对象的方法时,会先判断该方法上是否加了@Transcational注解

4)如果加了,那么则利用事务管理器创建一个数据库连接

5)并且修改数据库连接的antocommit属性为false,禁止此连接的自动提交,这是实现Spring事务非常关键的一步

6)然后执行当前方法,当前方法会执行sql

7)执行完当前方法后,如果没有出现异常,那么就提交事务

8)如果出现了异常并且这个异常需要回滚,那么就会回滚事务,否则就会提交事务

9)Spring事务的隔离级别就是对应数据库的隔离级别

10)Spring事务的隔离级别是基于数据库连接来做的

 

10.Spring事务的传播机制是什么?

多个事务方法相互调用时,事务如何在这些方法之间进行传播,Spring提供了7种不同的传播特性,来保证事务的正常执行。

REQUIRED:是默认的传播特性,如果当前没有事务,则新建一个事务,如果当前存在事务,则加入这个事务。

SUPPORTS:当前存在事务,则加入事务,当前不存在事务,则以非事务的方式运行。

 

11.Java线程池的拒绝策略有哪些?

 

12.java内存模型(JMM)介绍:

由于JVM运行程序的实体是线程,而每个线程创建JVM时都会为其创建一个【工作内存】,工作内存是每个线程的【私有数据区域】,而Java内存模型规定所有的变量都存储在【主内存】中,主内存是共享数据区域,所有线程都可以访问。但线程对变量的操作都必须在工作内存中进行,这就首先要将变量从主内存拷贝到线程自己的工作内存中,然后对变量进行操作,操作完成后再将变量写回主内存,【不能直接操作主内存中的变量】,各个线程中的工作内存中存储着主内存的【变量副本拷贝】,不同的线程无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成。

 

13.CAS是什么?

 

14.阻塞队列知道吗?

 

15.@Autowired是什么?

@Autowired表示某个属性【是否需要进行依赖注入】,可以写在属性和方法上。注解中的required默认为true,表示如果没有对象注入给属性则抛出异常。@Autowired加在某个属性上,Spring在进行bean的生命周期过程中,在属性填充这一步,会基于实例化出来的对象,对该对象中加了@Autowired的属性自动给属性赋值。

 

16.@Resource是什么?

@Resource与@Autowired类似,也是用来【依赖注入】的,@Resource是Java层面提供的注解,@Autowired是Spring层面提供的注解,它们依赖注入的底层实现逻辑也不同。

@Resource如果name属性有值,那么Spring直接根据所指定的name值去Spring容器找bean对象,如果找到了则成功,没找到则报错。

@Resource如果name属性没值,则:先判断该属性名字在Spring容器中是否存在Bean对象,如果存在则成功找到Bean对象注入,如果不存在,

则根据属性类型去Spring容器找Bean对象,找到一个则进行注入。(ps: 还是需要结合看源码去理解( ))

 

17.Spring中的bean是线程安全的吗?

1)单例bean的情况:如果在类中声明成员变量,并且有读写操作(有状态),就会线程不安全(*就是相当于说,同一个实例对象可能会被多个线程访问,因此就会存在线程安全问题)。但是只要把成员变量【声明在方法中】,那么这时候单例bean就是线程安全的(栈封闭,栈是线程私有的)。

 

18.Spring如何处理线程并发问题?

1)设置为多例(prototype) ,这样不同的线程都会从Spring容器中拿到不同的实例对象

2)将成员变量放在ThreadLocal当中

3)使用同步锁,在相应的代码块加入同步锁

4)将成员变量声明在方法中

 

19.Spring实例化bean有多少种方式?

1.构造器方式(反射):即通过xml配置:<bean class="xxxx.xxx.xx" / > 或者@Component注解实现,这是由Spring控制的。

2.静态工厂方式(factory-method),这是由程序员自己控制的

3.实例工厂方式(@Bean),这是由程序员自己控制的

4.FactoryBean方式(它是一个接口),这是由程序员自己控制的

 

20.什么是bean装配?什么是bean的自动装配?

多个对象之间,会有各种各样的依赖关系。比如A依赖于B和C,B依赖于D和E,且C又依赖于F。这时候,假如我们向Spring容器要个A的对象,

那么这时候Spring容器不是只创建一个空的新的A对象给我们,而是会对A对象进行"装配",也就是将A依赖的各个对象,这种嵌套的依赖,都给组装起来,组成一个完整的对象再返回给我们,这就是bean的装配,Spring帮我们自动做这些事情,所以也称为自动装配(前提:打上相应的注解或者写配置)。

如果不进行装配就返回,那么我们拿到一个空的A对象,那也没意义。

 

21.Spring如何解决Bean的循环依赖的?

采用三级缓存解决的。(三级缓存,就是三个Map)

1)一级缓存:存储完整的Bean

2) 二级缓存:避免多重循环依赖的情况下重复创建动态代理(为什么要创建动态代理?( ))

3) 三级缓存:

a.缓存是函数式接口:通过lambda把方法传进去(具体还是得看到源码才会更加清晰())(把bean的实例和bean的名字传进去(aop创建))

b.不会立即调:(如果在实例化后立即调用的话:所有的aop,不管bean是否循环依赖都会在实例化后创建proxy,正常Bean其实Spring还是希望遵循生命周期在初始化创建动态代理,只有循环依赖才创建???(不太理解( )))

c.会在 ABA(第二次getBean(A)才会去调用三级缓存)(如果实现了aop才会创建动态代理,如果没有实现依然返回的bean的实例)

d.放入二级缓存(为了避免重复创建)

 

22.Bean的生产顺序是由什么决定的?

Bean的创建顺序是由BeanDefinition的注册顺序来决定的,当然【依赖关系】也会影响Bean的创建顺序。

BeanDefinition的注册顺序是由什么决定的?

-主要是由注解(配置)的解析顺序来决定的(得需要看源码)

1.@Configuration

2.@Component

3.@Bean

4.@Import

(未完待续。。。)

 

23.@Component, @Controller, @Repository, @Service有何区别? 

这四个注解,本质上其实都算是@Component注解,因为我们的项目代码一般分为三层,控制层(@Controller),业务层(@Service),数据访问层(@Repository)。通过不同的注解,能让我们的项目代码可读性更好,更清晰。

 

24.为什么要用线程池?解释下线程池参数?

1)降低资源消耗,提高线程利用率,降低创建和销毁线程的消耗。

2) 提高响应速度,任务来了,直接有线程可用可执行,而不是先创建线程,再执行。

3)提高线程的可管理性,线程是稀缺资源,使用线程池可以统一分配调优监控

 

25.Redis底层数据结构是如何用跳表来存储的?

跳表:将【有序链表】改造为支持近似“折半查找”算法,可以快速地进行插入,删除,查找操作。

 

26.什么是BeanDefinition?

BeanDefinition表示Bean定义,Spring根据BeanDefinition来创建Bean对象,BeanDefinition有很多的属性来描述Bean,它是Spring中非常核心的概念

 

27.AOP是什么?

AOP就是面向切面编程,是一种非常适合在【无需修改业务代码】的前提下,对某个或某些业务【增加统一的功能】,比如日志记录,权限控制,事务管理等等。能很好地使得代码解耦,提升开发效率。

AOP中的核心概念:

Advice:【通知】,建议,在Spring中通过定义Advice来定义【代理逻辑】。

PointCut:【切点】,表示表示Advice对应的代理逻辑应用在哪个类,哪个方法上。

Advisor:它等于 Advice + PointCut,表示代理逻辑和切点的一个整体,程序员可以定义或封装一个Advisor,来定义切点和代理逻辑。

Weaving:【织入】,将Advice代理逻辑在【源代码级别】【嵌入到切点】的【过程】,就叫做【织入】。

Target:表示【目标对象】,也即【【被】代理对象】,在AOP生成的【代理对象】会持有目标对象。

Join Point:表示【连接点】,在Spring AOP中,就是方法的执行点。

 

AOP的工作原理:AOP是发生在Bean的生命周期过程中的:

1.Spring生成Bean对象时,先实例化出来一个对象,也就是target对象

2.再对target对象进行属性填充

3.在初始化后步骤中,会判断target对象有没有对应的切面

4.如果有切面,就表示当前的target对象需要进行AOP

5.通过Cglib或JDK动态代理机制生成一个【代理对象】,作为最终的bean对象

6.代理对象中有一个target属性指向了target对象

 

28.谈谈你对SpringBoot的理解:

用来快速开发Spring的一个脚手架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。

........

 

29.Java运行时一个类是什么时候被加载的?

一个类在什么时候开始被加载,在java虚拟机规范中并没有进行强制约束,交给了虚拟机去自由实现。HotSpot虚拟机中是采用【按需加载】,在需要用到该类的时候才去加载。

 

30.Redis的过期键的删除策略?

首先来看下通用的过期键删除策略:

1)定时删除(主动删除策略):定时删除策略对内存是最友好的:通过使用定时器,定时删除策略可以保证过期键会尽可能快地被删除,并释放过期键所占用的内存。

另一方面,它的缺点是,它对CPU时间是最不友好的:在过期键比较多的情况下,删除过期键会占用相当一部分CPU时间,在内存不紧张但是CPU时间非常紧张的情况下,将CPU时间用在删除和当前任务无关的过期键上,无疑会对服务器的响应时间和吞吐量造成影响。

2)惰性删除(被动删除策略):只有当访问一个key时,才会判断该key是否过期,过期则清除。该策略可以最大化地节省CPU资源,但是却对内存非常不友好。因为我只要没有访问到过期key,那么它就会一直在内存中不会被删除,这就相当于是内存泄漏。

3)定期删除(主动删除策略):每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少个过期键,以及要检查多少个数据库,则由算法决定。

Redis采用的过期键删除策略:

惰性删除 + 定期删除这两种,通过这两种方式配合使用,使得服务器可以很好地在合理使用CPU时间和避免内存浪费空间之间取得平衡。

 

31.@Autowired,@Resource, @Qualifier这几个注解之间的相同点和区别?

首先得区分byName和byType的区别,比如,假设有:<bean id="userServiceImpl" class="cn.com.bochy.service.impl.UserServiceImpl" autowire="byName"> </bean> <bean id="userDao" class="cn.com.bochy.dao.impl.UserDaoImpl"> </bean>

在这段代码中,byName就是通过Bean的id或者name去找,byType就是按照Bean的Class类型去找。

相同点:

 

@Resource的作用相当于@Autowired,均可标注在字段或者属性的setter方法上。

不同点:

1)提供方不同:@Autowired是由Spring提供,@Resource是Java自带的,J2EE提供。

2)注入方式不同:@Autowired只按照byType(就是根据Bean的Class类型)注入,@Resource默认按照byName注入,然后也提供按照byType注入。

3)属性不同:@Autowired按照类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。另外,

如果我们想使用按名称装配(也就是byName),那么可以结合@Qualifier注解一起使用

@Resource有两个中重要的属性: name和type。name属性指定byName, 如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法 上,即默认取属性名作为bean名称寻找依赖对象。需要注意的是,@Resource如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时,@Resource注解 会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。

@Qualifier的作用

这是官方的介绍

This annotation may be used on a field or parameter as a qualifier for

candidate beans when autowiring. It may also be used to annotate other

custom annotations that can then in turn be used as qualifiers.

简单的理解就是:
(1)在使用@Autowire自动注入的时候,加上@Qualifier(“test”)可以指定注入哪个对象;
(2)可以作为筛选的限定符,我们在做自定义注解时可以在其定义上增加@Qualifier,用来筛选需要的对象。

附上代码示例辅助理解:

 

 

 

 

 

32.说一下Spring的事务传播行为

Spring的事务传播行为说的是,当一个事务方法被另一个事务方法调用时(多个事务同时存在的时候),这个事务方法该如何进行(或者说Spring如何处理)

未完待续。。。

 

33.什么是缓存雪崩?

在高并发下,【大量】缓存key【在同一时间失效】,大量请求直接落在数据库上,导致数据库宕机。

解决方案:

1)【随机】设置key失效时间,避免大量key集体失效

2) 若是集群部署,可将热点数据均匀分布在不同的Redis库中也能避免key全部失效问题

3) 不设置过期时间(*这个方法感觉也不是很好)

4) 跑定时任务,在缓存失效前刷新进新的缓存 

5) 通过其他一些依赖隔离组件(比如Hystrix,类似"保险丝")为后端限流并降级

 

34.mysql聚簇索引和非聚簇索引的区别

对于innodb存储引擎来说,可以使用B+树来作为索引的数据结构,聚簇索引有以下特点:

1)使用记录主键值的大小进行记录和页的排序

2)其叶子节点存储的是完整的用户记录(所谓完整的用户记录,就是指这个记录中存储了所有列的值)

InnoDB存储引擎会自动帮我们创建聚簇索引,并且在InnoDB中,聚簇索引就是数据的存储方式(所有的用户记录都存在了叶子节点),也就是所谓的

"索引即数据,数据即索引"

对于【非聚簇索引】来说,它是根据某个表的【非主键列】去创建的,然后它的叶子节点存储的是指定的列(1或多个)的值和主键的值,也就是说,它的叶子节点存储的不是完整的用户记录(如果再存完整用户记录的话,那么开销太大了)。因为这种以非主键列的大小为排序而建立的B+树需要执行【回表操作】才可以定位到完整的用户记录,所以这种B+树索引也称为【二级索引】或者【辅助索引】。

 

35.MySQL的隔离级别有哪些?

READ-UNCOMMITTED 读取未提交的内容 (会有脏读,不可重复读,幻读的问题)

READ-COMMITTED 读取已提交的内容 (不会出现脏读,但可能会有 不可重复读,幻读)

REPEATABLE-READ 可重复读 (不会出现脏读,不可重复读,但可能有幻读)

SERIALIZABLE 可串行化 (脏读,不可重复读,幻读都不会出现)

附上xmind梳理的截图:

 

 

 

 

 

 

 

在上面的描述中,要注意的是,不可重复读和幻读的差别。不可重复读:一个事务A读取某个数据并且未提交,这时候B事务进来【修改】了这个数据,之后A事务重新读取,发现跟前面那次读取的不一样,这是不可重复读;而幻读是:同样是类似上面那个场景:事务A读取【符合某搜索条件】的某个(些)数据且未提交,这时候同样是B事务进来,但这时候,他是【插入了】符合该搜索条件的记录,之后,事务A再次去读取符合某搜索条件的记录的时候,会发现读取的记录跟之前不一样(变多了),这就是幻读。

总结:MySQL默认的【隔离级别】是【可重复读】,并且通过MVCC来解决【幻读】问题。

 

 

36.什么是MySQL的主从复制?

MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,  从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。

 

37.MySQL复制的原理是什么?(未完待续)

 

38.什么是索引条件下推?

假设创建了如下索引: create index idx on user(name, age), 即为name和age这两个字段建立了联合索引

假设有这样的一条查询语句:select * from user where name like '张%' and age = 10,

并继续假如:我们通过name like '张%' 找到了两条记录,其中一条的age是10(满足条件),另外一条age是15(不满足条件)。

如果没有索引下推的话,我们需要进行两次回表操作,如果有索引下推的话,我们找到刚刚上述的两条记录后,会更进一步去判断age符不符合,

这样又能筛掉一条记录,从而只需一次回表。这就是索引下推的好处,它可以减少因为回表操作而带来的性能损耗。

 

39.注册中心的核心功能原理是什么?

【服务注册】:当服务启动,通过Rest请求的方式向 Nacos Server 注册自己的服务

【服务心跳】:Nacos Client 会维护一个【定时心跳】【持续通知】 Nacos Server,默认5s一次,如果 Nacos Server在一定时间内没有收到心跳,那么会将该服务健康状态设置为false,超过一定更长时间后,就会把该服务剔除掉

【服务发现】:Nacos Client 会有一个定时任务,实时去 Nacos Server 拉取健康的服务

【服务停止】:Nacos Client 会主动通过Rest方式向 Nacos Server 发送一个注销请求

 

40.线上几百万消息积压如何处理?

 

 

41.JVM对象何时会进入老年代?

1)对象年龄,对象每经历一个mirror gc后,年龄就会加15,默认情况当年龄加到15,就会进入老年代

2)动态对象年龄判断,当Survivor区域中,如果存活对象的大小超过当前区域大小的50%,那么按照对象年龄排序,大于等于这批对象最小年龄的对象都会进入老年代

3)大对象直接进入老年代,采用这个策略原因(*要复制移动对象,对象越大,越消耗性能)如下:

 


 

4)Survivor区域对象空间不足:

 

42.MQ如何保证消息发送成功(如何保证消息不丢失):

 


 

 


43.秒杀系统超卖等问题如何解决?

背景知识:

 

 

解决方案:

 

44.JVM什么情况下会触发 Full GC?

1.手动调用System.gc()

 

2.老年代空间不足

 

3.CMS 在 GC 时出现 promotion failed 和 concurrent mode failure


 

4.堆中分配了很大的对象

5.其他情况....

 

45.Spring事务的常见失效场景

@Transactional是自定义注解,它底层是通过aop和反射技术来实现的。

它帮我们开启事务,并且执行我们的目标方法,并且如果是执行成功,那么会帮我们提交事务,如果在执行我们的目标方法时出了异常,它就会捕获到并回滚事务。因此,如果我们在我们的目标方法取捕获了异常,那么这时候它会检测不到异常,从而提交事务,这样我们就看到事务失效了。

 

46.为什么TCP需要三次握手而不是两次?

这是为了防止已经失效的请求报文突然又传到服务器引起错误。

假设采用两次握手连接,客户端向服务端发送了一个SYN包来请求建立连接,因为某些未知的原因,并没有到达服务器,在中间某个网络节点产生了滞留,为了建立连接客户端会重发SYN包,这次的数据包正常送达,服务端回复SYN+ACK之后建立起了连接。但是这时候第一包数据阻塞的网络节点突然恢复,第一包SYN包又送达到服务端,这时服务端会误认为是客户端又发起了一个新的连接,从而在两次握手之后进入等待状态。服务端认为是两个连接,而客户端认为是一个连接,造成了状态不一致。如果在三次握手的情况下,服务端收不到最后的ACK包,自然不会认为连接建立成功。

所以三次握手本质上说,就是为了解决网络信道不可靠的问题。为了在不可靠的信道上建立可靠的连接,经过三次握手之后,客户端和服务端都进入了数据传输状态。

 

47.JVM调优的目的是什么?

主要是为了减少GC(特别是Full GC,因为Full GC的STW时间长,因为Mirror GC的STW时间很短)的次数,从而减少 Stop The World, STW就是当JVM触发GC的时候,会暂时停掉所有用户线程,然后由垃圾回收线程进行可用对象和垃圾对象的判断标记和清除,在STW的时候,对于用户来说,就是会感觉到网站出现卡顿,体验很差。因此要进行JVM调优的目的就是减少GC的次数,进而减少STW的时间。

 

48.JVM有哪些垃圾回收算法?

1.标记-清除算法:把垃圾内存标记出来,然后将这些打了标记的垃圾内存进行回收。缺陷:会产生大量内存碎片。

2.复制算法:为了解决标记清除算法带来的内存碎片问题,就产生了复制算法。复制算法将内存分为大小相等的两半,每次只使用其中一半。垃圾回收时,将当前存放对象的那一半将剩余的存活对象都复制到另一半,这时候这一半的内存全部可以回收不会产生碎片。 缺陷:效率低下,而且如果存活对象越多,那么它的效率越低。

3.标记压缩算法

 

49.JVM中哪些是线程共享区?

方法区和堆区。

 

50.为什么TCP需要三次握手而不是两次?

在网络传输会有这样一种情况:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到【连接释放】以后的某个时间才到达server。本来这是一个【早已失效】的报文段。但server收到此失效的连接请求报文段后,就【误认为】是client再次发出的一个新的连接请求。于是就向client发出确认报文段,【同意建立连接】。假设不采用“三次握手”而采用“两次握手”,那么只要server发出确认,新的连接就建立了。但又由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接,所以实际不会创建连接,从而避免不必要的资源浪费。因此三次握手的主要目的是防止server端一直等待,浪费资源。
 

51.为什么TCP需要四次挥手?

TCP连接是【全双工】的,因此【每个方向】都必须【单独进行关闭】:当一方完成它的数据发送任务后就发送一个FIN来终止这个方向的连接,对端收到后回复一个ACK报文,这样双向就需要四次交互。

Client主动关闭的情况下,Server收到Client的FIN报文时,仅仅表示Client没有数据发送给Server了;但Server可能还有数据要发送给Client,所以Server可能并不会立即关闭SOCKET,而是先回复一个ACK报文,告诉Client“你发的FIN报文我收到了”。只有等到Server所有的报文都发送完了,才发送FIN报文。也就是说,被动关闭方的ACK和FIN报文多数情况下都是分开发送的,所以需要四次交互。

52.euraka,zookeeper, nacos 这三个组件都可以作为注册中心,它们之间有什么区别?

 

53.谈谈你对CAP理论的理解

Consistency(一致性)
即更新操作成功后,所有节点在同一时间的数据完全一致。

Availability(可用性)
即服务一直可用,而且是正常响应时间。系统能够很好地为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。我一定会给您返回数据,不会给你返回错误,但不保证数据最新,强调的是不出错。

Partition Tolerance(分区容错性)
即分布式系统在遇到某个节点或者网络分区故障的时候仍然能够对外提供满足一致性和可用性的服务。分区容错性要求能够使应用虽然是一个分布式系统,而看上去却好像是一个可以正常运转的整体。

 

54.谈谈你对BASE理论的理解

BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结, 是基于CAP定理逐步演化而来的。BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。接下来看一下BASE中的三要素:

 

posted @ 2022-06-22 21:32  痴狂coding  阅读(50)  评论(0)    收藏  举报