Java常见面试题 Java面试必看 (一)

十一、Spring Boot/Spring Cloud

104、什么是 spring boot?

Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
    Spring Boot 简化了基于 Spring 的应用开发,通过少量的代码就能创建一个独立的、产品级别的 Spring 应用。 Spring Boot 为 Spring 平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始。Spring Boot 的核心思想就是约定大于配置,多数 Spring Boot 应用只需要很少的 Spring 配置。采用 Spring Boot 可以大大的简化你的开发模式,所有你想集成的常用框架,它都有对应的组件支持。

105、为什么要用 spring boot?

Spring Boot解决的问题:
        (1) Spring Boot使编码变简单
        (2) Spring Boot使配置变简单
        (3) Spring Boot使部署变简单
        (4) Spring Boot使监控变简单
        (5) 解决了Spring的不足

Spring Boot的主要特性:
        (1)遵循“习惯优于配置”的原则,使用Spring Boot只需要很少的配置,大部分的时候我们直接使用默认的配置即可; 
        (2)项目快速搭建,可以无需配置的自动整合第三方的框架; 
        (3)可以完全不使用XML配置文件,只需要自动配置和Java Config; 
        (4)内嵌Servlet容器,降低了对环境的要求,可以使用命令直接执行项目,应用可用jar包执行:java -jar; 
        (5)提供了starter POM, 能够非常方便的进行包管理, 很大程度上减少了jar hell或者dependency hell; 
        (6)运行中应用状态的监控; 
        (7)对主流开发框架的无配置集成; 
        (8)与云计算的天然继承;

Spring Boot的核心功能:
        (1)独立运行的Spring项目
        (2)内嵌的Servlet容器
        (3)提供starter简化Manen配置
        (4)自动配置Spring
        (5)应用监控
        (6)无代码生成和XML配置

106、spring boot 核心配置文件是什么?

Spring Boot 中有以下两种配置文件
        bootstrap (.yml 或者 .properties)
        application (.yml 或者 .properties)

区别:
        Spring Cloud 构建于 Spring Boot 之上,在 Spring Boot 中有两种上下文,一种是 bootstrap, 另外一种是 application, bootstrap 是应用程序的父上下文,也就是说 bootstrap 加载优先于 applicaton。bootstrap 主要用于从额外的资源来加载配置信息,还可以在本地外部配置文件中解密属性。这两个上下文共用一个环境,它是任何Spring应用程序的外部属性的来源。bootstrap 里面的属性会优先加载,它们默认也不能被本地相同配置覆盖。

107、spring boot 配置文件有哪几种类型?它们有什么区别?

Spring Boot 支持两种格式的配置文件:YML、Properties,其中YAML的数据结构比properties更清晰。

区别:
        properties格式:key=value
        yml格式:1. 不同“等级” 用冒号隔开。2. 次等级的前面是空格,不能使用制表符(tab)。3. 冒号之后如果有值,那么冒号和值之间至少有一个空格,不能紧贴着

108、spring boot 有哪些方式可以实现热部署?

Spring Boot 实现热部署
        使用 Spring Loaded
        使用 spring-boot-devtools

109、jpa 和 hibernate 有什么区别?

Jpa是一种规范,而Hibernate是它的一种实现。
    hibernate有JPA没有的特性,JPA的注解已经是hibernate的核心,hibernate只提供了一些补充。
    hibernate 的效率更快,JPA 有更好的移植性,通用性

110、什么是 spring cloud?

spring cloud 可以认为是一种分布式服务的框架,它为开发人员提供了快速构建分布式系统的常用模式的一些工具,比如说配置管理、服务的注册与发现、服务调用的负载均衡、资源隔离、熔断降级等等,spring cloud为这些提供了一阵套完整的解决方案。

111、spring cloud 断路器的作用是什么?

在分布式环境下hystrix通过添加延迟容错和失败容差逻辑来帮助我们处理服务之间的交互。它会隔绝各服务间的调用,防止出现雪崩现象并提供fallback失败备用方案,以此提高我们服务集群的弹性。同时使系统具有自动降级和自动恢复服务的效果。

112、spring cloud 的核心组件有哪些?

spring cloud中五大核心组件Eureka、Ribbon、Feign、Hystrix、Zuul

Eureka是微服务架构中的注册中心,专门负责服务的注册与发现。Eureka Client组件专门负责将服务的信息注册到Eureka Server中,而Eureka Server是一个注册中心,里面有一个注册表,保存了各服务所在的机器和端口号。各个服务启动时,Eureka Client都会将服务注册到Eureka Server,并且Eureka Client还可以反过来从Eureka Server拉取注册表,从而知道其他服务在哪。
    Feign的关键机制是使用了动态代理。如果你对某个接口定义了@FeignClient注解,Feign就会针对这个接口创建一个动态代理;接着你要是调用那个接口,本质就是会调用Feign创建的动态代理;Feign的动态代理会根据你在接口上的@RequestMapping等注解,来动态构造出你要请求的服务的地址;针对这个地址,发起请求,解析相应;
    Ribbon的作用是负载均衡,会帮你在每次请求时选择一台机器,均匀的把请求分发到各个机器上,默认使用Round Robin轮询算法;
    Hystrix是隔离、熔断以及降级的一个框架。发起请求是通过Hystrix的线程池来走的,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题;
    Zuul也就是微服务网关。这个组件是负责网络路由的,一般微服务架构中都必然设计一个网关在里面,像android、ios、pc前端、微信小程序、h5等,不用关心后端有几百个服务,就知道有一个网关,所有请求都往网关走,网关会根据请求中的一些特征,将请求转发给后端的各个服务。有一个网关之后,还有很多好处,比如做统一的降级、限流、认证授权、安全等等。

十二、Hibernate

113、为什么要使用 hibernate?

Hibernate的优点:
        1、对象化。
            hibernate可以让开发人员以面相对象的思想来操作数据库。jdbc只能通过SQL语句将元数据传送给数据库,进行数据操作。而hibernate可以在底层对元数据和对象进行转化,使得开发者只用面向对象的方式来存取数据即可。
        2、更好的移植性。
            hibernate使用xml或JPA的配置以及数据库方言等等的机制,使得hibernate具有更好的移植性,对于不同的数据库,开发者只需要使用相同的数据操作即可,无需关心数据库之间的差异。而直接使用JDBC就不得不考虑数据库差异的问题。
        3、开发效率高。
            hibernate提供了大量的封装(这也是它最大的缺点),很多数据操作以及关联关系等都被封装的很好,开发者不需写大量的sql语句,这就极大的提高了开发者的开发效率。
        4、缓存机制的使用。
            hibernate提供了缓存机制(session缓存,二级缓存,查询缓存),对于那些改动不大且经常使用的数据,可以将它们放到缓存中,不必在每次使用时都去查询数据库,缓存机制对提升性能大有裨益。

114、什么是 ORM 框架?

ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法。

常用的ORM框架:Hibernate、iBATIS

115、hibernate 中如何在控制台查看打印的 sql 语句?

spring.jpa.properties.hibernate.show_sql=true          //控制台是否打印
    spring.jpa.properties.hibernate.format_sql=true        //格式化sql语句
    spring.jpa.properties.hibernate.use_sql_comments=true  //指出是什么操作生成了该语句

116、hibernate 有几种查询方式?

hibernate查询的6种方法。
        1.HQL查询,2.对象化查询Criteria方法,3.动态查询DetachedCriteria,4.例子查询,5.sql查询,6.命名查询

117、hibernate 实体类可以被定义为 final 吗?

是的,你可以将Hibernate的实体类定义为final类,但这种做法并不好。因为Hibernate会使用代理模式在延迟关联的情况下提高性能,如果你把实体类定义成final类之后,因为 Java不允许对final类进行扩展,所以Hibernate就无法再使用代理了,如此一来就限制了使用可以提升性能的手段。不过,如果你的持久化类实现了一个接口而且在该接口中声明了所有定义于实体类中的所有public的方法到话,你就能够避免出现前面所说的不利后果

118、在 hibernate 中使用 Integer 和 int 做映射有什么区别?

1,使用基本数据类型的好处
        a),使用基本数据类型意味着你所定义的属性不允许为空,这样你在获取该属性的时候就不可能会得到一个null值。
        b),int在java中占32/64 bits,而Integer占了16个字节,所以使用Integer在性能方面要比int差一些。
     
    2,使用包装类的好处
        a),当我们不想给这个属性设置任何值的时候,我们可以给它一个null值(前提是数据库的字段允许插入NULL)。
        b),我们可以在pojo类中使用验证注解对属性的值做校验(例如: javax.validation.constraints.NotNull)

总结:
        a),如果你的数据库字段是允许为空的,使用包装类。如果不允许为空,使用包装的时候,如果你往数据库插入null值,此时就会抛出异常。然后你就可以对异常进行捕获并处理。
        b),使用基本数据类型的时候,如果字段是NULL,那么JDBC会返回0,但是这里会有一个问题。有可能0在你的业务逻辑代表着特定含义,这时候就可能出现一些意想不到的后果。
        c),建议使用包装类型

119、hibernate 是如何工作的?

hibernate核心接口
        session:负责被持久化对象CRUD操作
        sessionFactory:负责初始化hibernate,创建session对象
        configuration:负责配置并启动hibernate,创建SessionFactory
        Transaction:负责事物相关的操作
        Query和Criteria接口:负责执行各种数据库查询
        
    hibernate工作原理:
        1.通过Configuration config = new Configuration().configure();//读取并解析hibernate.cfg.xml配置文件
        2.由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>读取并解析映射信息
        3.通过SessionFactory sf = config.buildSessionFactory();//创建SessionFactory
        4.Session session = sf.openSession();//打开Sesssion
        5.Transaction tx = session.beginTransaction();//创建并启动事务Transation
        6.persistent operate操作数据,持久化操作
        7.tx.commit();//提交事务
        8.关闭Session
        9.关闭SesstionFactory

120、get()和 load()的区别?

load加载方式
        当使用load方法来得到一个对象时,此时hibernate会使用延迟加载的机制来加载这个对象
        当使用session.load() 方法加载一个对象的时候,并不会发出SQL语句,这个对象其实就是一个代理对象,而这个代理对象只是保存实体对象的id值,只有当我们使用这个对象,得到其他属性的时候,这个时候才会发出SQL语句,从数据库中查询相对于的对象

get加载方式
        相对于load的延迟加载方式,get就直接的多,当我们使用session.get()方法来得到一个对象时,不管我们使不使用这个对象,此时都会发出sql语句去从数据库中查询出来

如果对象不存在(报错区别)
        如果这个对象不存,通过get方式,去数据库中查询出该对象,但是这个不存在,所以id值页不存在,所以此时对象是null,所以就会报NullPointException的异常了(空指针异常)。
        如果使用load方式来加载对象,当我们试图得到这个不存在的对象 的id值的时候,此时会报ObjectNotFoundException异常(对象未找到异常)

对象都不存在为什么报的异常不同?
        是因为load的延迟加载机制,使用load时,此时的user对象是一个代理对象,仅仅保存了当前的这个id值,当我们试图得到该对象的username属性时,这个属性其实是不存在的,所以就会报出ObjectNotFoundException这个异常了

121、说一下 hibernate 的缓存机制?

Hibernate缓存包括两大类:Hibernate一级缓存和 Hibernate二级缓存。
        1.Hibernate一级缓存又称为“Session的缓存”。Session缓存内置不能被卸载,Session的缓存是事务范围的缓存(Session对象的生命周期通常对应一个数据库事务或者一个应用事务)。一级缓存中,持久化类的每个实例都具有唯一的 OID。
        2.Hibernate二级缓存又称为“SessionFactory的缓存”。由于  SessionFactory 对象的生命周期和应用程序的整个过程对应,因此 Hibernate  二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。第二级缓存是可选的,是一个可配置的插件,默认下 SessionFactory不会启用这个插件。Hibernate提供了  org.hibernate.cache.CacheProvider接口,它充当缓存插件与 Hibernate之间的适配器。

122、hibernate 对象有哪些状态?

hibernate里对象有三种状态:
        1,Transient 瞬时 :对象刚new出来,还没设id,设了其他值。
        2,Persistent 持久:调用了save()、saveOrUpdate(),就变成Persistent,有id
        3,Detached  脱管 : 当session  close()完之后,变成Detached。

123、在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?

getCurrentSession () 使用当前的session 
    openSession()重新建立一个新的session

结论:
        在一个应用程序中,如果DAO 层使用Spring 的hibernate 模板,通过Spring 来控制session 的生命周期,则首选getCurrentSession ()。如果使用的是getCurrentSession来创建session的话,在commit后,session就自动被关闭了,不用再session.close()了。但是如果使用的是openSession方法创建的session的话,那么必须显示的关闭session,也就是调用session.close()方法。getcurrentSession()的Session 在第一次被使用的时候,即第一次调用getCurrentSession()的时候,其生命周期就开始。然后她被Hibernate绑定到当前线程。当事物结束的时候,不管是提交还是回滚,Hibernate会自动把Session从当前线程剥离,并且关闭。若再次调用 getCurrentSession(),会得到一个新的Session,并且开始一个新的工作单元。

124、hibernate 实体类必须要有无参构造函数吗?为什么?

是的。 原因:

Hibernate框架会调用这个默认构造方法来构造实例对象,即Class类的newInstance方法 ,这个方法就是通过调用默认构造方法来创建实例对象的 。当查询的时候返回的实体类是一个对象实例,是Hibernate动态通过反射生成的。反射的Class.forName(“className”).newInstance()需要对应的类提供一个无参构造方法,必须有个无参的构造方法将对象创建出来,单从Hibernate的角度讲 他是通过反射创建实体对象的 所以没有默认构造方法是不行的,另外Hibernate也可以通过有参的构造方法创建对象。

提醒一点:
        如果你没有提供任何构造方法,虚拟机会自动提供默认构造方法(无参构造器),但是如果你提供了其他有参数的构造方法的话,虚拟机就不再为你提供默认构造方法,这时必须手动把无参构造器写在代码里,否则new Xxxx()是会报错的,所以默认的构造方法不是必须的,只在有多个构造方法时才是必须的,这里“必须”指的是“必须手动写出来”。

十三、Mybatis

125、mybatis 中 #{}和 ${}的区别是什么?

mybatis中#{}和${}的区别:
        1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
        2. $将传入的数据直接显示生成在sql中。
        3. #方式能够很大程度防止sql注入。$方式无法防止Sql注入。
        4.$方式一般用于传入数据库对象,例如传入列名.
        5.一般能用#的就别用$. MyBatis排序时使用order by 动态参数时需要注意,用$而不是#

126、mybatis 有几种分页方式?

mybatis的4种分页方式:
        数组分页
        借助Sql语句limit进行分页
        拦截器分页
        RowBounds分页

127、RowBounds 是一次性查询全部结果吗?为什么?

是的,因为在数据量比较小的情况下,效率比较高。

128、mybatis 逻辑分页和物理分页的区别是什么?

1:逻辑分页 内存开销比较大,在数据量比较小的情况下效率比物理分页高;在数据量很大的情况下,内存开销过大,容易内存溢出,不建议使用
    2:物理分页 内存开销比较小,在数据量比较小的情况下效率比逻辑分页还是低,在数据量很大的情况下,建议使用物理分页

129、mybatis 是否支持延迟加载?延迟加载的原理是什么?

支持;    延迟加载:
        先从单表查询、需要时再从关联表去关联查询,大大提高数据库性能。
    
    延迟加载原理:
        延迟加载主要是通过动态代理的形式实现,通过代理拦截到指定方法,执行数据加载。MyBatis延迟加载主要使用Javassist,Cglib实现。

130、说一下 mybatis 的一级缓存和二级缓存?

①、一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
    ②、二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

131、mybatis 和 hibernate 的区别有哪些?

(1)hibernate是全自动,而mybatis是半自动
        hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。
    (2)hibernate数据库移植性远大于mybatis
        hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(Oracle、MySQL等)的耦合性,而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性而用了很多某数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。
    (3)hibernate拥有完整的日志系统,mybatis则欠缺一些
        hibernate日志系统非常健全,涉及广泛,包括:sql记录、关系异常、优化警告、缓存提示、脏数据警告等;而mybatis则除了基本记录功能外,功能薄弱很多。
    (4)mybatis相比hibernate需要关心很多细节
        hibernate配置要比mybatis复杂的多,学习成本也比mybatis高。但也正因为mybatis使用简单,才导致它要比hibernate关心很多技术细节。mybatis由于不用考虑很多细节,开发模式上与传统jdbc区别很小,因此很容易上手并开发项目,但忽略细节会导致项目前期bug较多,因而开发出相对稳定的软件很慢,而开发出软件却很快。hibernate则正好与之相反。但是如果使用hibernate很熟练的话,实际上开发效率丝毫不差于甚至超越mybatis。
    (5)sql直接优化上,mybatis要比hibernate方便很多
        由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而hibernate的sql很多都是自动生成的,无法直接维护sql;虽有hql,但功能还是不及sql强大,见到报表等变态需求时,hql也歇菜,也就是说hql是有局限的;hibernate虽然也支持原生sql,但开发模式上却与orm不同,需要转换思维,因此使用上不是非常方便。总之写sql的灵活度上hibernate不及mybatis。
    (6)缓存机制上,hibernate要比mybatis更好一些
        MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。而Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。

132、mybatis 有哪些执行器(Executor)?

Mybatis有三种基本的Executor执行器: SimpleExecutor、ReuseExecutor、BatchExecutor。
        SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
        ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
        BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。

作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。

133、mybatis 分页插件的实现原理是什么?

分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

134、mybatis 如何编写一个自定义插件?

确定要拦截的签名
        确定要拦截的对象,四大对象之一;
        确定拦截的方法和参数;
        实现Interceptor接口

定义插件类,实现拦截方法
        实现Interceptor接口的方法即可,通过Plugin工具类方便生成代理类,通过MetaObject工具类方便操作四大对象的属性,修改对应的值。
        
    配置
        最后配置自定义的插件

十四、RabbitMQ

135、rabbitmq 的使用场景有哪些?

(1)解耦
        比如订单-库存系统,传统的下订单过程是下订单成功之后,立即减少库存,对库存系统有着强依赖,倘若库存系统出现问题,调用库存系统失败,则数据回滚,导致订单创建失败。采用RabbitMQ的处理的过程,下订单成功之后,将消息写入消息队列,库存系统从消息队列里去取数据,执行自己减库存的操作,这样即便库存系统出现问题,订单依旧能够创建成功。但是这种方式容易造成订单与库存的数据不一致,要注意RabbitMQ的持久化或其它策略来保证数据的一致性。
    (2)异步处理
        比如用户注册后需要发送信息和邮件给用户的操作。如果采用传统方式,则注册成功之后发短信>发邮件两个串行操作,执行时间长。如果采用RabbitMQ的方式,注册成功之后将消息写入消息队列,写入的时间远小于发短信或邮件的时间,然后再去发短信和邮件,由于这两个操作基本同时进行,所以这两个操作可以看做是并行操作,大大节省时间
    (3)处理日志
        一个项目需要各种各样的日志,来记录操作,调用过程等,日志系统不要求实时性,使用消息队列处理就非常方便了
    (4)流量削峰
        消息队列是基于队列的,在秒杀活动中,当队列写入消息达到某一数值时,不再写入消息队列,而直接跳转到活动结束的页面,由于队列先进先出的这一特性,也能保证秒杀活动的秒杀顺序.

其他答案:

①. 跨系统的异步通信,所有需要异步交互的地方都可以使用消息队列。就像我们除了打电话(同步)以外,还需要发短信,发电子邮件(异步)的通讯方式。
    ②. 多个应用之间的耦合,由于消息是平台无关和语言无关的,而且语义上也不再是函数调用,因此更适合作为多个应用之间的松耦合的接口。基于消息队列的耦合,不需要发送方和接收方同时在线。在企业应用集成(EAI)中,文件传输,共享数据库,消息队列,远程过程调用都可以作为集成的方法。
    ③. 应用内的同步变异步,比如订单处理,就可以由前端应用将订单信息放到队列,后端应用从队列里依次获得消息处理,高峰时的大量订单可以积压在队列里慢慢处理掉。由于同步通常意味着阻塞,而大量线程的阻塞会降低计算机的性能。
    ④. 消息驱动的架构(EDA),系统分解为消息队列,和消息制造者和消息消费者,一个处理流程可以根据需要拆成多个阶段(Stage),阶段之间用队列连接起来,前一个阶段处理的结果放入队列,后一个阶段从队列中获取消息继续处理。
    ⑤. 应用需要更灵活的耦合方式,如发布订阅,比如可以指定路由规则。
    ⑥. 跨局域网,甚至跨城市的通讯(CDN行业),比如北京机房与广州机房的应用程序的通信。

136、rabbitmq 有哪些重要的角色?

RabbitMQ 中重要的角色有:生产者、消费者和代理:
        生产者:消息的创建者,负责创建和推送数据到消息服务器;
        消费者:消息的接收方,用于处理数据和确认消息;
        代理:就是 RabbitMQ 本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。

137、rabbitmq 有哪些重要的组件?

ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用。
    Channel(信道):消息推送使用的通道。
    Exchange(交换器):用于接受、分配消息。
    Queue(队列):用于存储生产者的消息。
    RoutingKey(路由键):用于把生成者的数据分配到交换器上。
    BindingKey(绑定键):用于把交换器的消息绑定到队列上。

138、rabbitmq 中 vhost 的作用是什么?

vhost 可以理解为虚拟 broker ,即 mini-RabbitMQ server。其内部均含有独立的 queue、exchange 和 binding 等,但最最重要的是,其拥有独立的权限系统,可以做到 vhost 范围的用户控制。当然,从 RabbitMQ 的全局角度,vhost 可以作为不同权限隔离的手段(一个典型的例子就是不同的应用可以跑在不同的 vhost 中)。

139、rabbitmq 的消息是怎么发送的?

首先客户端必须连接到 RabbitMQ 服务器才能发布和消费消息,客户端和 rabbit server 之间会创建一个 tcp 连接,一旦 tcp 打开并通过了认证(认证就是你发送给 rabbit 服务器的用户名和密码),你的客户端和 RabbitMQ 就创建了一条 amqp 信道(channel),信道是创建在“真实” tcp 上的虚拟连接,amqp 命令都是通过信道发送出去的,每个信道都会有一个唯一的 id,不论是发布消息,订阅队列都是通过这个信道完成的。

140、rabbitmq 怎么保证消息的稳定性?

提供了事务的功能。通过将 channel 设置为 confirm(确认)模式。

141、rabbitmq 怎么避免消息丢失?

消息持久化
    ACK确认机制
    设置集群镜像模式
    消息补偿机制

142、要保证消息持久化成功的条件有哪些?

声明队列必须设置持久化 durable 设置为 true.
    消息推送投递模式必须设置持久化,deliveryMode 设置为 2(持久)。
    消息已经到达持久化交换器。
    消息已经到达持久化队列。

以上四个条件都满足才能保证消息持久化成功

143、rabbitmq 持久化有什么缺点?

持久化的缺点就是降低了服务器的吞吐量,因为使用的是磁盘而非内存存储,从而降低了吞吐量。可尽量使用 ssd 硬盘来缓解吞吐量的问题。

144、rabbitmq 有几种广播类型?

三种广播模式:
        fanout: 所有bind到此exchange的queue都可以接收消息(纯广播,绑定到RabbitMQ的接受者都能收到消息);
        direct: 通过routingKey和exchange决定的那个唯一的queue可以接收消息;
        topic:所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息;

145、rabbitmq 怎么实现延迟消息队列?

通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能;
    使用 RabbitMQ-delayed-message-exchange 插件实现延迟功能

146、rabbitmq 集群有什么用?

集群主要有以下两个用途:
        高可用:某个服务器出现问题,整个 RabbitMQ 还可以继续使用;
        高容量:集群可以承载更多的消息量。

147、rabbitmq 节点的类型有哪些?

磁盘节点:消息会存储到磁盘。
    内存节点:消息都存储在内存中,重启服务器消息丢失,性能高于磁盘类型。

148、rabbitmq 集群搭建需要注意哪些问题?

各节点之间使用“--link”连接,此属性不能忽略。
    各节点使用的 erlang cookie 值必须相同,此值相当于“秘钥”的功能,用于各节点的认证。
    整个集群中必须包含一个磁盘节点。

149、rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?    不是,原因有以下两个:
        存储空间的考虑:如果每个节点都拥有所有队列的完全拷贝,这样新增节点不但没有新增存储空间,反而增加了更多的冗余数据;
        性能的考虑:如果每条消息都需要完整拷贝到每一个集群节点,那新增节点并没有提升处理消息的能力,最多是保持和单节点相同的性能甚至是更糟。

150、rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?

如果唯一磁盘的磁盘节点崩溃了,不能进行以下操作:
        不能创建队列
        不能创建交换器
        不能创建绑定
        不能添加用户
        不能更改权限
        不能添加和删除集群节点

唯一磁盘节点崩溃了,集群是可以保持运行的,但你不能更改任何东西。

151、rabbitmq 对集群节点停止顺序有要求吗?

RabbitMQ 对集群的停止的顺序是有要求的,应该先关闭内存节点,最后再关闭磁盘节点。如果顺序恰好相反的话,可能会造成消息的丢失。

十五、Kafka

152、kafka 可以脱离 zookeeper 单独使用吗?为什么?

kafka 不能脱离 zookeeper 单独使用,因为 kafka 使用 zookeeper 管理和协调 kafka 的节点服务器。

153、kafka 有几种数据保留的策略?

kafka 有两种数据保存策略:按照过期时间保留和按照存储的消息大小保留。

154、kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?

这个时候 kafka 会执行数据清除工作,时间和大小不论哪个满足条件,都会清空数据。

155、什么情况会导致 kafka 运行变慢?

cpu 性能瓶颈、磁盘读写瓶颈、网络瓶颈

156、使用 kafka 集群需要注意什么?

集群的数量不是越多越好,最好不要超过 7 个,因为节点越多,消息复制需要的时间就越长,整个群组的吞吐量就越低。集群数量最好是单数,因为超过一半故障集群就不能用了,设置为单数容错率更高。

十六、Zookeeper

157、zookeeper 是什么?

zookeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 google chubby 的开源实现,是 hadoop 和 hbase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

158、zookeeper 都有哪些功能?

集群管理:监控节点存活状态、运行请求等。
    主节点选举:主节点挂掉了之后可以从备用的节点开始新一轮选主,主节点选举说的就是这个选举的过程,使用 zookeeper 可以协助完成这个过程。
    分布式锁:zookeeper 提供两种锁:独占锁、共享锁。独占锁即一次只能有一个线程使用资源,共享锁是读锁共享,读写互斥,即可以有多线线程同时读同一个资源,如果要使用写锁也只能有一个线程使用。zookeeper可以对分布式锁进行控制。
    命名服务:在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。

159、zookeeper 有几种部署模式?

zookeeper 有三种部署模式:
        单机部署:一台集群上运行;
        集群部署:多台集群运行;
        伪集群部署:一台集群启动多个 zookeeper 实例运行。

160 、zookeeper 怎么保证主从节点的状态同步?

zookeeper 的核心是原子广播,这个机制保证了各个 server 之间的同步。实现这个机制的协议叫做 zab 协议。 zab 协议有两种模式,分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,zab 就进入了恢复模式,当领导者被选举出来,且大多数 server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 server 具有相同的系统状态。

161、集群中为什么要有主节点?

在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,所以就需要主节点。

162、集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?

可以继续使用,单数服务器只要没超过一半的服务器宕机就可以继续使用。

163、说一下 zookeeper 的通知机制?

客户端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些客户端会收到 zookeeper 的通知,然后客户端可以根据 znode 变化来做出业务上的改变。

十七、MySql

164、数据库的三范式是什么?

第一范式:强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项。
    第二范式:要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。
    第三范式:任何非主属性不依赖于其它非主属性。

165、一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?

表类型如果是 MyISAM ,那 id 就是 18。
    表类型如果是 InnoDB,那 id 就是 15。
    InnoDB 表只会把自增主键的最大 id 记录在内存中,所以重启之后会导致最大 id 丢失。

166、如何获取当前数据库版本?

使用 select version() 获取当前 MySQL 数据库版本。

167、说一下 ACID 是什么?

Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
    Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
    Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
    Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

168、char 和 varchar 的区别是什么?

char(n) :固定长度类型,比如订阅 char(10),当你输入"abc"三个字符的时候,它们占的空间还是 10 个字节,其他 7 个是空字节。
    char 优点:效率高;缺点:占用空间;适用场景:存储密码的 md5 值,固定长度的,使用 char 非常合适。
    varchar(n) :可变长度,存储的值是每个值占用的字节再加上一个用来记录其长度的字节的长度。
    所以,从空间上考虑 varcahr 比较合适;从效率上考虑 char 比较合适,二者使用需要权衡。

169、float 和 double 的区别是什么?

float 最多可以存储 8 位的十进制数,并在内存中占 4 字节。
    double 最可可以存储 16 位的十进制数,并在内存中占 8 字节。

170、mysql 的内连接、左连接、右连接有什么区别?

内连接关键字:inner join;左连接:left join;右连接:right join。
    内连接是把匹配的关联数据显示出来;左连接是左边的表全部显示出来,右边的表显示出符合条件的数据;右连接正好相反。

171、mysql 索引是怎么实现的?

索引是满足某种特定查找算法的数据结构,而这些数据结构会以某种方式指向数据,从而实现高效查找数据。
    具体来说 MySQL 中的索引,不同的数据引擎实现有所不同,但目前主流的数据库引擎的索引都是 B+ 树实现的,B+ 树的搜索效率,可以到达二分法的性能,找到数据区域之后就找到了完整的数据结构了.。

172、怎么验证 mysql 的索引是否满足需求?

使用 explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。
    explain 语法:explain select * from table where type=1。

173、说一下数据库的事务隔离?

MySQL 的事务隔离是在 MySQL. ini 配置文件里添加的,在文件的最后添加:transaction-isolation = REPEATABLE-READ
    可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。

READ-UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)。
    READ-COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读)。
    REPEATABLE-READ:可重复读,默认级别,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读)。
    SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。

脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
    不可重复读 :是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。
    幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。

174、说一下 mysql 常用的引擎?

InnoDB 引擎:InnoDB 引擎提供了对数据库 acid 事务的支持,并且还提供了行级锁和外键的约束,它的设计的目标就是处理大数据容量的数据库系统。MySQL 运行的时候,InnoDB 会在内存中建立缓冲池,用于缓冲数据和索引。但是该引擎是不支持全文搜索,同时启动也比较的慢,它是不会保存表的行数的,所以当进行 select count(*) from table 指令的时候,需要进行扫描全表。由于锁的粒度小,写操作是不会锁定全表的,所以在并发度较高的场景下使用会提升效率的。

MyIASM 引擎:MySQL 的默认引擎,但不提供事务的支持,也不支持行级锁和外键。因此当执行插入和更新语句时,即执行写操作的时候需要锁定这个表,所以会导致效率会降低。不过和 InnoDB 不同的是,MyIASM 引擎是保存了表的行数,于是当进行 select count(*) from table 语句时,可以直接的读取已经保存的值而不需要进行扫描全表。所以,如果表的读操作远远多于写操作时,并且不需要事务的支持的,可以将 MyIASM 作为数据库引擎的首选。

175、说一下 mysql 的行锁和表锁?

MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。

表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。
    行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。

176、说一下乐观锁和悲观锁?

乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。
    悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。

数据库的乐观锁需要自己实现,在表里面添加一个 version 字段,每次修改成功值加 1,这样每次修改的时候先对比一下,自己拥有的 version 和数据库现在的 version 是否一致,如果不一致就不修改,这样就实现了乐观锁。

177、mysql 问题排查都有哪些手段?

使用 show processlist 命令查看当前所有连接信息。
    使用 explain 命令查询 SQL 语句执行计划。
    开启慢查询日志,查看慢查询的 SQL。

178、如何做 mysql 的性能优化?

为搜索字段创建索引。
    避免使用 select *,列出需要查询的字段。
    垂直分割分表。
    选择正确的存储引擎。

十八、Redis

179、redis 是什么?都有哪些使用场景?

Redis是一个开源的 key—value型 单线程 数据库,支持string、list、set、zset和hash类型数据。默认端口:6379,默认数据库数量:16

1、热点数据的缓存
    2、限时业务的运用
    3、计数器相关问题
    4、排行榜相关问题
    5、分布式锁
    6、延时操作
    7、分页、模糊搜索
    8、点赞、好友等相互关系的存储
    9、队列

180、redis 有哪些功能?

redis可以当缓存使用、用于消息队列、计数器、热点数据、排行等

181、redis 和 memecache 有什么区别?

1、存储方式:memecache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小redis有部份存在硬盘上,这样能保证数据的持久性,支持数据的持久化(笔者注:有快照和AOF日志两种持久化方式,在实际应用的时候,要特别注意配置文件快照参数,要不就很有可能服务器频繁满载做dump)。
    2、数据支持类型:redis在数据支持上要比memecache多的多。
    3、使用底层模型不同:新版本的redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
    4、运行环境不同:redis目前官方只支持Linux 上去行,从而省去了对于其它系统的支持,这样的话可以更好的把精力用于本系统 环境上的优化,虽然后来微软有一个小组为其写了补丁。但是没有放到主干上。

182、redis 为什么是单线程的?

redis 核心就是 如果我的数据全都在内存里,我单线程的去操作 就是效率最高的,为什么呢,因为多线程的本质就是 CPU 模拟出来多个线程的情况,这种模拟出来的情况就有一个代价,就是上下文的切换,对于一个内存的系统来说,它没有上下文的切换就是效率最高的。redis 用 单个CPU 绑定一块内存的数据,然后针对这块内存的数据进行多次读写的时候,都是在一个CPU上完成的,所以它是单线程处理这个事。在内存的情况下,这个方案就是最佳方案

183、什么是缓存穿透?怎么解决?

缓存穿透:
        缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

解决方案:
        有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

184、redis 支持的数据类型有哪些?

redis有五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)、sorted set(有序集合)。

185、redis 支持的 java 客户端都有哪些?

Redisson,Jedis,lettuce等等,官方推荐使用Redisson。

186、jedis 和 redisson 有哪些区别?

Jedis 和 Redisson 都是Java中对Redis操作的封装。Jedis 只是简单的封装了 Redis 的API库,可以看作是Redis客户端,它的方法和Redis 的命令很类似。Redisson 不仅封装了 redis ,还封装了对更多数据结构的支持,以及锁等功能,相比于Jedis 更加大。但Jedis相比于Redisson 更原生一些,更灵活。

Jedis 是Java 实现的Redis 客户端,它的API提供了全面的类似于Redis 原生命令的支持。相比于其他Redis 封装框架更加原生。它的使用主要是使用JedisPool
    Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。

187、怎么保证缓存和数据库数据的一致性?

双删加超时
        在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。这样最差的情况是在超时时间内存在不一致,当然这种情况极其少见,可能的原因就是服务宕机。此种情况可以满足绝大多数需求。 当然这种策略要考虑redis和数据库主从同步的耗时,所以在第二次删除前最好休眠一定时间,比如500毫秒,这样毫无疑问又增加了写请求的耗时

异步淘汰缓存
        通过读取binlog的方式,异步淘汰缓存。好处:业务代码侵入性低,将缓存与数据库不一致的时间尽可能缩小。

188、redis 持久化有几种方式?

redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。

189、redis 怎么实现分布式锁?

使用redis的setNX命令实现分布式锁

190、redis 分布式锁有什么缺陷?

1. setnx和expire的非原子性
        Redis 2.6.12以上版本为set指令增加了可选参数,伪代码如下:set(key,1,30,NX),这样就可以取代setnx指令。
    2. 超时后使用del 导致误删其他线程的锁

3. 出现并发的可能性

191、redis 如何做内存优化?

一、尽量使用hash

二、根据业务场景,考虑使用BITMAP
        只适合01型标签;
        需要位移位与标签的字典表,属于额外开销,但相对而言字典表offset数字可共享redis数字池,比直接存字符串要省空间。
        牺牲时间换空间:维护字典表;入库需要对应转化;出库计算也需要转换。
        
    三、其他:
        Redis提供内存回收策略,根据使用的情况可以选择适当的回收策略,比如过期数据清除,expire设置数据过期时间;
        Redis提供内存共享策略,服务器启动时,会自动创建0-9999的数字对象,其他地方使用,可以直接引用。

192、redis 淘汰策略有哪些?

1)voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
    2)volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
    3)volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
    4)allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
    5)allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
    6)no-enviction(驱逐):禁止驱逐数据

193、redis 常见的性能问题有哪些?该如何解决?

1.master写内存快照,seve命令调度rdbsave函数,会阻塞主线程的工程,当快照比较大的时候对性能的影响是非常大的,会间断性暂停服务 。所以master最好不要写内存快照。

2.master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响master重启时的恢复速度。master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个slave开启AOF备份数据,策略每秒为同步一次。

3.master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂的服务暂停现象。

4.redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,slave和master最好在同一个局域网内。

5.<–Slave1<–Slave2<–Slave3…….,这样的结构也方便解决单点故障问题,实现Slave对Master的替换,也即,如果Master挂了,可以立马启用Slave1做Master,其他不变。

十九、JVM

194、说一下 jvm 的主要组成部分?及其作用?

JVM 整体组成可分为以下四个部分
        类加载器(ClassLoader)
        运行时数据区(Runtime Data Area)
        执行引擎(Execution Engine)
        本地库接口(Native Interface)

各个组成部分的用途:
        程序在执行之前先要把java代码转换成字节码(class文件),jvm首先需要把字节码通过一定的方式 类加载器(ClassLoader) 把文件加载到内存中 运行时数据区(Runtime Data Area) ,而字节码文件是jvm的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine) 将字节码翻译成底层系统指令再交由CPU去执行,而这个过程中需要调用其他语言的接口 本地库接口(Native Interface)来实现整个程序的功能,这就是这4个主要组成部分的职责与功能。

195、说一下 jvm 运行时数据区?

JVM内存区域分为五个部分,分别是堆,方法区,虚拟机栈,本地方法栈,程序计数器。

1、堆。 堆是Java对象的存储区域,任何用new字段分配的Java对象实例和数组,都被分配在堆上,Java堆可使用-Xms -Xmx进行内存控制,值得一提的是从JDK1.7版本之后,运行时常量池从方法区移到了堆上。
    2、方法区。它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,方法区在JDK1.7版本及以前被称为永久代,从JDK1.8永久代被移除。
    3、虚拟机栈。虚拟机栈中执行每个方法的时候,都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。
    4、本地方法栈。与虚拟机栈发挥的作用相似,相比于虚拟机栈为Java方法服务,本地方法栈为虚拟机使用的Native方法服务,执行每个本地方法的时候,都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。
    5、程序计数器。指示Java虚拟机下一条需要执行的字节码指令。

以上五个区域是Java虚拟机内存划分情况,其中方法区和堆被JVM中多个线程共享,比如类的静态常量就被存放在方法区,供类对象之间共享,虚拟机栈,本地方法栈,pc寄存器是每个线程独立拥有的,不会与其他线程共享。 
    所以Java在通过new创建一个类对象实例的时候,一方面会在虚拟机栈中创建一个该对象的引用,另一方面会在堆上创建类对象的实例,然后将对象引用指向该对象的实例。对象引用存放在每一个方法对应的栈帧中。

196、说一下堆栈的区别?

1.栈内存存储的是局部变量而堆内存存储的是实体;
    2.栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;
    3.栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。

197、队列和栈是什么?有什么区别?

队列(Queue):是限定只能在表的一端进行插入和另一端删除操作的线性表 
    栈(Stack):是限定只能在表的一端进行插入和删除操作的线性表

队列和栈的规则 
        队列:先进先出 
        栈:先进后出 
    队列和栈的遍历数据速度 
        队列:基于地址指针进行遍历,而且可以从头部或者尾部进行遍历,但不能同时遍历,无需开辟空间,因为在遍历的过程中不影响数据结构,所以遍历速度要快 
        栈:只能从顶部取数据,也就是说最先进入栈底的,需要遍历整个栈才能取出来,遍历数据时需要微数据开辟临时空间,保持数据在遍历前的一致性

198、什么是双亲委派模型?

当需要加载一个类的时候,子类加载器并不会马上去加载,而是依次去请求父类加载器加载,一直往上请求到最高类加载器:启动类加载器。当启动类加载器加载不了的时候,依次往下让子类加载器进行加载。当达到最底下的时候,如果还是加载不到该类,就会出现ClassNotFound的情况。

好处:保证了程序的安全性。例子:比如我们重新写了一个String类,加载的时候并不会去加载到我们自己写的String类,因为当请求上到最高层的时候,启动类加载器发现自己能够加载String类,因此就不会加载到我们自己写的String类了。

199、说一下类加载的执行过程?

当Java程序需要使用某个类时,如果该类还未被加载到内存中,JVM会通过加载、连接(验证、准备和解析)、初始化三个步骤来对该类进行初始化。

类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。加载完成后,Class对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后JVM对类进行初始化,包括:1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句。

200、怎么判断对象是否可以被回收?

1.引用计数法
        给每一个对象添加一个引用计数器,每次引用计数器就加1,当引用失效的时候就减1,当计数器的值为0的时候,就可以对该对象进行回收。

2.可达性分析算法
        将一系列的gc roots对象作为起始点,从这些节点向下搜索,搜索走过的路径称为是引用链,当gc roots对象到一个对象没有引用链的时候,称为这个对象是不可达的,此对象是不可用的,就可以进行回收。

201、java 中都有哪些引用类型?

①强引用(StrongReference)
        就是指在程序代码中普遍存在的,类似Object obj = new Object()这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
    ②软引用(SoftRefernce)
        对于软引用关联着的对象,如果内存充足,则垃圾回收器不会回收该对象,如果内存不够了,就会回收这些对象的内存。
    ③弱引用(WeakReference)
        用来描述非必须的对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发送之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
    ④虚引用(PhantomReference)
        虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个持有虚引用的对象,和没有引用几乎是一样的,随时都有可能被垃圾回收器回收。当试图通过虚引用的get()方法取得强引用时,总是会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。

202、说一下 jvm 有哪些垃圾回收算法?

标记-清除算法(Mark-Sweep)
      标记-清除算法采用从根集合(GC Roots)进行扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的对象,进行回收,标记-清除算法不需要进行对象的移动,只需对不存活的对象进行处理,在存活对象比较多的情况下极为高效,但由于标记-清除算法直接回收不存活的对象,因此会造成内存碎片。

复制算法(Copying)
      复制算法的提出是为了克服句柄的开销和解决内存碎片的问题。它开始时把堆分成 一个对象 面和多个空闲面, 程序从对象面为对象分配空间,当对象满了,基于copying算法的垃圾 收集就从根集合(GC Roots)中扫描活动对象,并将每个 活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存。

标记-整理算法(Mark-compact)
      标记-整理算法采用标记-清除算法一样的方式进行对象的标记,但在清除时不同,在回收不存活的对象占用的空间后,会将所有的存活对象往左端空闲空间移动,并更新对应的指针。标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是却解决了内存碎片的问题

分代收集算法
      分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),在堆区之外还有一个代就是永久代(Permanet Generation)。老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。

203、说一下 jvm 有哪些垃圾回收器?

JVM(HotSpot) 7种垃圾收集器

1.Serial收集器
        Serial收集器是最基本、发展历史最悠久的收集器。是单线程的收集器。它在进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集完成。
        Serial收集器依然是虚拟机运行在Client模式下默认新生代收集器,对于运行在Client模式下的虚拟机来说是一个很好的选择。
    2.ParNew收集器
        ParNew收集器其实就是Serial收集器的多线程版本,除了使用多线程进行垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数、收集算法、Stop The Worl、对象分配规则、回收策略等都与Serial 收集器完全一样。
        ParNew收集器是许多运行在Server模式下的虚拟机中首选新生代收集器,其中有一个与性能无关但很重要的原因是,除Serial收集器之外,目前只有ParNew它能与CMS收集器配合工作。
    3.Parallel Scavenge(并行回收)收集器
        Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器
    4.Serial Old 收集器
        Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记整理算法。这个收集器的主要意义也是在于给Client模式下的虚拟机使用。
    5.Parallel Old 收集器
        Parallel Old 是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。这个收集器在1.6中才开始提供。
    6.CMS收集器
        CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求
    7. G1收集器
        使用G1收集器时,Java堆的内存布局是整个规划为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region的集合。

204、详细介绍一下 CMS 垃圾回收器?

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求

CMS收集器是基于“标记-清除”算法实现的。它的运作过程相对前面几种收集器来说更复杂一些,整个过程分为4个步骤:
        (1)初始标记
        (2)并发标记
        (3)重新标记
        (4)并发清除
    其中,初始标记、重新标记这两个步骤仍然需要“Stop The World”.CMS收集器主要优点:并发收集,低停顿。

CMS三个明显的缺点:
        (1)CMS收集器对CPU资源非常敏感。CPU个数少于4个时,CMS对于用户程序的影响就可能变得很大,为了应付这种情况,虚拟机提供了一种称为“增量式并发收集器”的CMS收集器变种。所做的事情和单CPU年代PC机操作系统使用抢占式来模拟多任务机制的思想
        (2)CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。在JDK1.5的默认设置下,CMS收集器当老年代使用了68%的空间后就会被激活,这是一个偏保守的设置,如果在应用中蓝年代增长不是太快,可以适当调高参数-XX:CMSInitiatingOccupancyFraction的值来提高触发百分比,以便降低内存回收次数从而获取更好的性能,在JDK1.6中,CMS收集器的启动阀值已经提升至92%。
        (3)CMS是基于“标记-清除”算法实现的收集器,手机结束时会有大量空间碎片产生。空间碎片过多,可能会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前出发FullGC。为了解决这个问题,CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollection开关参数(默认就是开启的),用于在CMS收集器顶不住要进行FullGC时开启内存碎片合并整理过程,内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间变长了。虚拟机设计者还提供了另外一个参数-XX:CMSFullGCsBeforeCompaction,这个参数是用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的(默认值为0,标识每次进入Full GC时都进行碎片整理)

205、新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?

新生代垃圾收集器
        Serial、ParNew、Parallel Scavenge
    老年代收集器
        Serial Old、Parallel Old、CMS、G1 收集器
        
    新生代:大多数对象在eden区生产、很多对象的生命周期很短、每次新生代的垃圾回收(minor gc)后只有少量对象存活所以选用的是复制算法、只需要少量的复制成本就可以完成回收
    老年代:old generation在新生代中经历了n次垃圾回收后仍然存活的对象、会被放到老年代、该区域对象存活的几率比较高,老年代的垃圾回收(Major gc)通常使用 标记-清理或者标记-整理算法,整堆的回收(包括young和old)称为full gc
    永久代: perm generation主要存放元数据、eg. class, method的元信息、与垃圾回收要回收的关系不大、相对新生代和老年代、改区域对垃圾回收的影响较小

206、简述分代垃圾回收器是怎么工作的?

分代垃圾回收机制,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。我们将对象分为三种状态:年轻代、年老代、持久代。JVM将堆内存划分为 Eden、Survivor 和 Tenured/Old 空间。

垃圾回收过程:
        1、新创建的对象,绝大多数都会存储在Eden中,
        2、当Eden满了(达到一定比例)不能创建新对象,则触发垃圾回收(GC),将无用对象清理掉,然后剩余对象复制到某个Survivor中,如S1,同时清空Eden区
        3、当Eden区再次满了,会将S1中的不能清空的对象存到另外一个Survivor中,如S2,同时将Eden区中的不能清空的对象,也复制到S1中,保证Eden和S1,均被清空。
        4、重复多次(默认15次)Survivor中没有被清理的对象,则会复制到老年代Old(Tenured)区中,
        5、当Old区满了,则会触发一个一次完整地垃圾回收(FullGC),之前新生代的垃圾回收称为(minorGC)

207、说一下 jvm 调优的工具?

Jconsole,jProfile,VisualVM
        Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用。对垃圾回收算法有很详细的跟踪。
        JProfiler:商业软件,需要付费。功能强大。
        VisualVM:JDK自带,功能强大,与JProfiler类似。推荐。

208、常用的 jvm 调优的参数都有哪些?

(1)-Xms20M
        表示设置JVM启动内存的最小值为20M,必须以M为单位
    (2)-Xmx20M
        表示设置JVM启动内存的最大值为20M,必须以M为单位。将-Xmx和-Xms设置为一样可以避免JVM内存自动扩展。大的项目-Xmx和-Xms一般都要设置到10G、20G甚至还要高
    (3)-verbose:gc
        表示输出虚拟机中GC的详细情况
    (4)-Xss128k
        表示可以设置虚拟机栈的大小为128k
    (5)-Xoss128k
        表示设置本地方法栈的大小为128k。不过HotSpot并不区分虚拟机栈和本地方法栈,因此对于HotSpot来说这个参数是无效的
    (6)-XX:PermSize=10M
        表示JVM初始分配的永久代(方法区)的容量,必须以M为单位
    (7)-XX:MaxPermSize=10M
        表示JVM允许分配的永久代(方法区)的最大容量,必须以M为单位,大部分情况下这个参数默认为64M
    (8)-Xnoclassgc
        表示关闭JVM对类的垃圾回收
    (9)-XX:+TraceClassLoading
        表示查看类的加载信息
    (10)-XX:+TraceClassUnLoading
        表示查看类的卸载信息
    (11)-XX:NewRatio=4
        表示设置 年轻代(包括Eden和两个Survivor区)/老年代 的大小比值为1:4,这意味着年轻代占整个堆的1/5
    (12)-XX:SurvivorRatio=8
        表示设置2个Survivor区:1个Eden区的大小比值为2:8,这意味着Survivor区占整个年轻代的1/5,这个参数默认为8
    (13)-Xmn20M
        表示设置年轻代的大小为20M
    (14)-XX:+HeapDumpOnOutOfMemoryError
        表示可以让虚拟机在出现内存溢出异常时Dump出当前的堆内存转储快照
    (15)-XX:+UseG1GC
        表示让JVM使用G1垃圾收集器
    (16)-XX:+PrintGCDetails
        表示在控制台上打印出GC具体细节
    (17)-XX:+PrintGC
        表示在控制台上打印出GC信息
    (18)-XX:PretenureSizeThreshold=3145728
        表示对象大于3145728(3M)时直接进入老年代分配,这里只能以字节作为单位
    (19)-XX:MaxTenuringThreshold=1
        表示对象年龄大于1,自动进入老年代,如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象在年轻代的存活时间,增加在年轻代被回收的概率。
    (20)-XX:CompileThreshold=1000
        表示一个方法被调用1000次之后,会被认为是热点代码,并触发即时编译
    (21)-XX:+PrintHeapAtGC
        表示可以看到每次GC前后堆内存布局
    (22)-XX:+PrintTLAB
        表示可以看到TLAB的使用情况
    (23)-XX:+UseSpining
        开启自旋锁
    (24)-XX:PreBlockSpin
        更改自旋锁的自旋次数,使用这个参数必须先开启自旋锁
    (25)-XX:+UseSerialGC
        表示使用jvm的串行垃圾回收机制,该机制适用于丹cpu的环境下
    (26)-XX:+UseParallelGC
        表示使用jvm的并行垃圾回收机制,该机制适合用于多cpu机制,同时对响应时间无强硬要求的环境下,使用-XX:ParallelGCThreads=<N>设置并行垃圾回收的线程数,此值可以设置与机器处理器数量相等。
    (27)-XX:+UseParallelOldGC
        表示年老代使用并行的垃圾回收机制
    (28)-XX:+UseConcMarkSweepGC
        表示使用并发模式的垃圾回收机制,该模式适用于对响应时间要求高,具有多cpu的环境下
     (29)-XX:MaxGCPauseMillis=100
        设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。
    (30)-XX:+UseAdaptiveSizePolicy
        设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低响应时间或者收集频率等,此值建议使用并行收集器时,一直打开

Java常见面试题 Java面试必看 (二)相关推荐

  1. Java常见面试题 Java面试必看 (一)

    本篇博客是本人收集网上Java相关的资料整理所得,仅供参考. 一.Java基础 1.JDK 和 JRE区别 JDK(Java Development Kit)是针对Java开发员的产品,是整个Java ...

  2. 网易资深安卓架构师:2021年Android常见面试题,面试必问

    开头 让我们一起来看看,字节跳动的第三面,面试官都问了什么?(第一二面的题目及答案已整理,需要的可以在文末领取) 从七月中旬开始,我前前后后差不多一共投递了八十份简历,到目前为止,我参加面试的面试有十 ...

  3. java常见面试题——java常见笔试题

    注:转载自http://www.cnblogs.com/yhason/archive/2012/05/08/2489932.html,版权归其所有! 5.String是最基本的数据类型吗? 基本数据类 ...

  4. 测试开发java常见面试题_Java常见面试题200+,学习、面试必备

    本套Java面试题,选取了企业面试最常问到的问题,可以做为Java工程师的面试宝典,也可以做为想要不断完善和扩充自己 java 技术的学习者. 主要包含: Java 基础.容器.多线程.反射.对象拷贝 ...

  5. 300+ Java常见面试题总结【JavaPub版】

    点赞再看,养成习惯 答案解析见文末 我是JavaPub,专注于面试.副业,技术人的成长记录. 这份[Java常见面试题总结]我想准备很久了,前面做面试官,后来自己也面了很多一线二线互联网公司,希望通过 ...

  6. Java常见面试题,2021年及答案汇总

    Java常见面试题,2021年及答案汇总 其实,博主还整理了,更多大厂面试题,直接下载吧 下载链接:高清172份,累计 7701 页大厂面试题 PDF 1.什么是ThreadPoolExecutor? ...

  7. Java常见面试题及答案汇总

    面临金三银四黄金跳槽季,不光是很多在职人员跃跃欲试,也有很多大学生积极地加入到应聘行列.作为技术出身的我们,找工作的一大前提就是技术是否能过关.而对于Java程序员来说,至少是两关的面试,这首个关卡就 ...

  8. java常见面试题及答案 1-10(基础篇)

    java常见面试题及答案 1.什么是Java虚拟机?为什么Java被称作是"平台无关的编程语言"? Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程.Java 源文件被 ...

  9. JAVA常见面试题及解答

    JAVA常见面试题及解答(精华)   1)transient和volatile是java关键字吗?(瞬联) 如果用transient声明一个实例变量,当对象存储时,它的值不需要维持.例如: class ...

最新文章

  1. 3、基于多播、安全认证的corosync集群(VIP、Httpd、Filesystem)
  2. MM模块在做GR的时候几个需要注意的地方
  3. getcwd和pwd为什么不一样_农村医保,为什么每个地区收费不一样?
  4. 9-4-插值查找-查找-第9章-《数据结构》课本源码-严蔚敏吴伟民版
  5. Linkedin领英如何避免封号
  6. 修改Oracle密码
  7. html css div圆角边框,div圆角边框的css写法
  8. ubuntu14.04中文楷体变默认字体
  9. Ubuntu 安装 Google Chrome 浏览器
  10. oracle 范鑫_快速理解数据库中的索引(Indexes in Database)
  11. Abnova 基因 FISH 探针丨CCND1(橙色)FISH 探针
  12. nodejs使用Moment.js操作日期时间
  13. For菜鸟文章:PE文件格式,qduwg翻译
  14. 工业交换机堆叠技术的优缺点
  15. 【第19天】内涵深厚才能妙语连珠
  16. [蓝桥杯python] 粘木棍:有N根木棍,需要将其粘贴成M个长木棍,使得最长的和最短的的差距最小。
  17. CPU 64位和32位
  18. 搜索引擎,你真的会用吗?
  19. Verilog VHDL三种建模描述方式——2选1数据选择器
  20. Java运算符与Scanner键盘输入

热门文章

  1. keepalived persistence_timeout参数意义 LVS Persistence 参数的作用
  2. Caused by: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction
  3. MBN与APN介绍学习
  4. 服务器部署openfire
  5. v-show不起作用
  6. 计算机报0x0000000a,win7蓝屏代码0x0000000a是什么意思 怎么解决
  7. 史上最好听的英文神曲歌
  8. c 语言 vk_return,GetAsyncKeyState(VK_RETURN)遇到
  9. UpdatePanel的使用方法[转]
  10. 商用密码最新标准和国家标准