Java面试题
Java面向对象特征
继承 封装 多态
继承 一个类继承了一另一个类可以采用他的方法以及他的属性
封装 (隐藏对象的信息,留出访问的接口)
多态 多态就是同一个接口,使用不同的实例而执行不同操作
Arraylist和linkedlist区别
ArrayList 是 底层采用 数组存储方式 查询快 删除 修改 新增 慢
linked list是底层采用链表形式 查询元素相当于慢 但删除 修改 新增快
Java 锁
sycn
@什么是Spring
Spring是Javabean框架 将mybatis 和mvc结合一起来的中间件 也叫万能胶
@Spring AOP 是什么
答:面向切面编程,当有多个业务过来时比如,A的核心逻辑是新增用户,B的核心逻辑是删除用户,但是他们都有一个共同体就是打印日志,
将打印日志封装成一切面,进行引入到A和B的业务逻辑中,避免的 重复代码
@Spring IOC是什么
答:IOC有控制反转,ABCD是个类,A类要采用B的业务逻辑,C类要采用D类的业务逻辑,在程序对象A初始化或者执行到某一个点上的时候,需要自己
主动去创建B对象或者使用已经存在的对象B,无论是创建还是使用对象B,控制权都在自己手上,所有,当对象A运行时需要对象B的时候,IOC容器会主动创建一个B注入到A
需要的地方
答:IOC依赖注入 当我们需要使用service或者dao层的时候,调用里面的方法时都要new对象进行调用,耦合性很高,采用注解方式,
将service和dao层丢入IOC容器中使用@Autowdon注解进行调用解决了低耦高效。
SpringBoot如何启动
答:src 项目路径下的project下创建一个类,打上@SpringBootapplicationn注解,编写Main方法 实现 调用SpringApplication.run方法即可启动
@NIO和IO的区别
答;NIO是面向缓冲 IO 面向流。 NIO是非堵塞的 IO是堵塞的 当一个线程调用read()时该线程被堵塞,直到数据读取完毕后放开,了。NIO是非堵塞的当在读取数据时,当前系统可以做其他业务处理。面向缓冲当NIO读取数据是会把数据存放在一个缓冲区内,需要什么数据就读什么数据,面向流一次性把需要的数据读取或数据完全写入。
@spring bean的生命周期
答:编写配置、读取配置、反射、@autowdon应用 、使用、销毁
@spring中支持的bean作用域
答:默认:单列:每个容器中只能有一个bean、requrst:bean被定义在每个http请求上,也就是说请求同一个都会复用这一个bean 、sesion:确保每一个session都有一个不同的baen,session过期,bean消失、aplication:bean被定义在servicecontxt生命周期中复用同一个bean、websock:bean被定义websock的生命周期中复用同一个bean
@spring bean是线程安全的吗
答:不安全 在举个例子 创建一个单列service在service中定义一个全局的conut并赋值 ,然后共享被调用 都能获取到里面的count值 所有线程是不安全的
@Spring使用了那些设计模式
工厂、单列模式、适配器模式、动态代理、装饰器模式
java锁
syncronized 用来多线程同时操作一组数据时,为了保证数据的准确性控制多个操作的顺序执行,以此来保证数据安全的变动
悲观锁
悲观锁认为被它保护的数据是极其不安全的,每时每刻都有可能变动,一个事务拿到悲观锁后(可以理解为一个用户),其他任何事务都不能对该数据进行修改,只能等待锁被释放才可以执行
乐观锁
乐观锁的“乐观情绪”体现在,它认为数据的变动不会太频繁。因此,它允许多个事务同时对数据进行变动。
但是,乐观不代表不负责,那么怎么去负责多个事务顺序对数据进行修改呢?乐观锁通常是通过在表中增加一个版本(version)或时间戳(timestamp)来实现,
其中,版本最为常用。事务在从数据库中取数据时,会将该数据的版本也取出来(v1),当事务对数据变动完毕想要将其更新到表中时,
会将之前取出的版本v1与数据中最新的版本v2相对比,如果v1=v2,那么说明在数据变动期间,没有其他事务对数据进行修改,此时,就允许事务对表中的数据进行
修改,并且修改时version会加1,以此来表明数据已被变动。如果,v1不等于v2,那么说明数据变动期间,数据被其他事务改动了,此时不允许数据更新到表中,
一般的处理办法是通知用户让其重新操作。不同于悲观锁,乐观锁是人为控制的
RabbitMQ消息丢失
答:为了保证消息从队列可靠的达到消费者,RabbitMQ提供了消息确认机制,authAck等于false时,
RabbitMQ 会等待消费者显式地回复确认信号后才从内存(或者磁盘)中移去消息(实质上是先打上删除标记,之后再删除)(自动确认),
当 autoAck 等于 true 时,因为这里我们使用了消费者自动消息确认机制。当 autoAck 等于 true 时,
RabbitMQ 会自动把发送出去的消息置为确认,然后从内存(或者磁盘)中删除,而不管消费者是否真正地消费到了这些消息 (手动确认)。
Redis 缓存击穿
答:指的是单个key在缓存中查不到,去数据库查询,这样如果数据量不大或者并发不大的话是没有什么问题的。
如果数据库数据量大并且是高并发的情况下那么就可能会造成数据库压力过大而崩溃
解决方案 :
第一种:通过synchronized+双重检查机制:某个key只让一个线程查询,阻塞其它线程
在同步块中,继续判断检查,保证不存在,才去查DB。
例如:
private static volaite Object lockHelp=new Object();
public String getValue(String key){undefined
String value=redis.get(key,String.class);
if(value=="null"||value==null||StringUtils.isBlank(value){undefined
synchronized(lockHelp){undefined
value=redis.get(key,String.class);
if(value=="null"||value==null||StringUtils.isBlank(value){undefined
value=db.query(key);
redis.set(key,value,1000);
}
}
}
return value;
}
缺点: 会阻塞其它线程
第二种方法:设置value永不过期
这种方式可以说是最可靠的,最安全的但是占空间,内存消耗大,并且不能保持数据最新 这个需要根据具体的业务逻辑来做
个人觉得如果要保持数据最新不放这么试试,仅供参考:
起个定时任务或者利用TimerTask 做定时,每个一段时间多这些值进行数据库查询更新一次缓存,当然前提时不会给数据库造成压力过大(这个很重要)
Redis 雪崩
雪崩指的是多个key查询并且出现高并发,缓存中失效或者查不到,然后都去db查询,从而导致db压力突然飙升,从而崩溃。
出现原因: 1 key同时失效
2 redis本身崩溃了
答:
1.在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。(跟击穿的第一个方案类似,但是这样是避免不了其它key去查数据库,只能减少查询的次数)
2.可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载。 mysql 存储引擎有那些
innodb myisam
Innodb和Myisam的区别
事务和外键
innodb:InnoDB具有事务,支持4个事务隔离级别,回滚,崩溃修复能力和多版本并发的事务安全,在应用中可以操作大量的INSERT或UPDATE操作
myisam:MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择
全文索引
Innodb不支持全文索引,如果一定要用的话,最好使用sphinx等搜索引擎。
myisam对中文支持的不是很好不过新版本的Innodb已经支持了。
Spring事物实现方式、隔离机制
答:使用事物在service业务层打上@Transactiona注解
(未提交读、提交不可重复读、可重复度、可串性化)
Spring事物传播机制
1.Requts 但没有事物时创建一个新事物,如果有事物则加入这个事物
2.当前有事物,则加入当前事物,如果没有事物就当没有事物执行
3.创建新事物,如果已经有事物了,则挂起档期数据
Spring事物什么时候会消失
1.在业务层使用this去调用事物则会消失
2.在非palubc方法中进行事物需要配置代理机制,如果不配拥有代理机制事物会消失
3.在数据库中没有事物 则会消失
4.在没有被Spring IOS容器管理的类中使用@Transactiona事物会消失
5.将事物的异常try chat上不往外抛出 事物会消失
5.什么时候bean自动化装配
在bean中打上@autoworker注解 赋值为 ByName BYtype 进行自动装配
redis的过期健的删除策略
情性过期:key和vlaue值存放在内存中,虽然是删除了,但内存中还是存在的,但第二次操作时才会去内存中进行删除,减少了cpu的压力
定期过期:redis每隔一段时间进行,扫描值如果已经删除了,它就会把内存中的进行删除
redis线程模式,单线程为什么快
1:它采用了纯内存操作
2:核心使用了非堵塞io多复用机制
3.使用单线程不需要线程上下切换,多想吃进行线程上下切换非常消耗内存
spring mvc工作流程
1.前端所有请求都会进dispatcherServlet
2.dispatcherServlet通过hadionMap进行适配器
3.@RequestMap通过适配器进行映射到对应的url
4.处理业务逻辑 ,处理完后返回modeandVue将controoler执行结果返回给dispatcherservlet将modelAndview传给viewResolovew视图解析器
4.dispatcjerServlet响应用户
mysql中 左链接 右链接 内链接
左连接:以左边的表为参照,显示所有数据,右边的表没有则显示null
右链接:以右边的表为参照,显示所有数据,左边的表没有则显示null
内连接: 显示两个表中有关联的所有数据
spring mvc 组件
答:HandlerMapping 通过前端传递过来的url进行解析
答:HandlerAdapter 通过解析后的url通过swppt进行查验controller中是否带有@ReqsutMaping 如果有 就进controoler里面的,如果没有就查找servlet中的service方法
SpringBoot自动配置原理
答:SpringBootApplication下面有@impot主键和@configgiler主键 和siop协议 通过config配置要启动的一些配置项调入IOS容器中管理,@impoot主键进行包扫描
扫描跟当前SpringbootApplication注解的同级的包,进行管理在包下打上@controller @service @configgiler注解都会被Spring进行管理
如何理解SpringBoot中的starter
答:可以理解为starter是第三方组件跟spring的一个桥连,比如说Springboot-starter-mongdb或mbatis ,它们把自动的配置通过@configgiler进行配置,比如说端口号啥的都进行默认配置了,
不需要我们在去第二配置,如不需要默认配置可以通过yml文件进行更改,像mybatis的链接数据库的url是必传的,没法提供默认值,不填的话会导致运行时异常
什么是嵌入服务器,为什么使用嵌入式服务器
答:嵌入式服务器就是jar中嵌入了tomcat,不需要我们自己再去搭建一个tomcat,然后把项目打包war包丢进行tomcat中运行,使用嵌入式服务器避免了tomcat的部署,一处编译到处运行的原则。
mysql锁有那些
答:共享锁、排它锁,
共享锁:在设置读锁后,其他的读锁事务也能进行读取,但是不能对数据进行增删除事务锁操作。
排他锁:一但加上了锁,其他的事务必须等锁放开后,进行读取,不然只能等待
表锁:表锁 将整张表进行加锁,但是的锁没有释放开,其他的锁或者事务都不能进行访问,或读取
行锁:行锁 将一整行数据进行加锁,加了锁的行不能被其他事务或锁进行访问,或读取
记录锁:针对一行数据进行加锁,前提是对唯一索引的数据进行加锁,加了记录锁后可以避免在数据查询时候被修改重复读的问题,也避免的在修改的时候,事务未提交被其他事务读取脏数据等问题。
mysql的基本特效
ACID:一致性 原子性 隔离性 持久性
一致性:确保数据在操作后的一致,A转账B A100 B200 A向B转账100,A为0 B为300 称之为一致性
原子性:操作数据时要么一起成功,要么一起失败
隔离性:一个事务修改在最终提交前,其他事务是不可见的
持久性:指的是事务提交后,所做的修改就会永久保存到数据库中
隔离级别:
读未提交、读已提交、mysql默认:提交可重复复读、串性化
ACID靠什么保证
A原则性由undo log日志保证,它记录了需要回滚的日志信息,事件回滚撤销已经执行完成的sql
什么是MACC
redis RDB和AOF 持久化 操作机制
RDB:redis数据存储到内存中,查询效率比较高,但是机器重启会导致数据丢失,采用快照模式进行一键保存数据,先写入临时文件中,写入成功后 在替换之前的文件 ,用二进制进行存储
优点:
1.整合redis数据将包含一个文件中.rbd文件,方便持久化
2.容灾性好,方便备份
2.性能最大化,fork子进程来完成写操作,让主进程进行处理命令,所以IO最大化,使用单独子进程来进行持久化,主进程不操作IO操作,保证redis高可用
AOF:
数据安全,redis中提供了3种同步策略,每秒同步、每修改同步和不同步,每秒同步也是异步完成的,其效率也是非常高的,所差的是一但系统宕机现象,那么这一秒钟之内修改的数据会丢失,而每修改同步,
我们可以将其视为同步持久化,每次发送数据变化,都会立刻记录磁盘中
redis事务实现
答:事务开启进入muiti命令执行,执行后会进入命令队列中进行对set,get方法做检查,是否正确,如果命令不正确关闭事务,如果命令正确进行事务执行,haspMap中的如果有Sting类型的错误,也会进行执行事务,
会把haspmap中的数据进行终止进行下面的数据
spring cloud Hystrix
隔离:将所以请求封装到一个独立的线程中执行,每个依赖服务维护一个小的线程池,在调用失败或超时的情况下可以断开依赖调用或返回指定的逻辑
熔断:当HystrixCommand请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务,断路器保持在开路状态一段时间后(默认5秒),自动切换到半开路状态(HALF-OPEN),这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED),否则重新切换到开路状态(OPEN)
降级:服务降级是指当请求后端服务出现异常的时候, 可以使用fallback方法返回的
rabbit MQ 死性队列
答:
1.当发生送者微服务发送消息时,消费者否定消息,当前消息会进入死性队列中
2.当消息设置TTL延迟属性时,时间超时会进入死刑队列中
3.当消息队列中的数据超过最大长度
rbbitMQ延迟消息
答:
当前业务发送消息,另一个业务需要隔一天进行消费,消防的这个业务端配置一个死性队列,然后当前发生消息的微服务设置一个消息延迟,延迟超时就会变成死性队列,把延迟的消息往消费端的那个死性队列中抛
分布式ACP
答:一致性:保证分布式集群的数据同步一致、
可用性:保证分布式中出现点单故障,确保服务的可正确使用、
分区蓉错性 :单网络出现故障后只可以进行二选一(要么数据一致性和分区蓉错AP、要么服务可用性和分区蓉错性CP)
数据库三大范式
1.(1NF)列不可再分
2.(2NF)属性完全依赖于主键
3.(3NF)属性不依赖于其他非主属性,属性直接依赖于主键
mybatis缓存机制
一级缓存:
sqlsession级别缓存,用于保存用户在一次会话过程中查询的结果,用户一次会话只能使用sqlsession,一级缓存是开启的,不允许关闭
二级缓存:
称为全局缓存,是 namespace 级别的缓存,是针对一个表的查询结果的存储,可以共享给所有针对这张表的查询的用户。也就是说对于nameSpace 级别的缓存,不同的 sqlsession 是可以共享这个缓存的。