【java常见面试题】

java面试题(个人总结,仅供参考)

1.Spring的相互依赖怎么解决?
答:类A依赖类B,类B又依赖类A,就形成了相互依赖,只有在setter注入的时候,可以用三级缓存来解决;
一级缓存:存放完整的bean;
二级缓存:避免重复创建动态代理。
三级缓存:缓存的函数接口
创建beanA的时候会调用getBean(A)来创建,这时候会去缓存中查找存不存在beanA,存在就直接返回,没有的话就开始走beanA的生命周期,首先开始实例化A,实例化之后将A的实列和名字加入到三级缓存中(aop创建),然后属性注入时发现beanB,创建beanB,调用getBean(B),实例化B的时候,加入三级缓存,然后B需要注入beanA,调用getBean(A),查询缓存中是否存在A,这时候三级缓存里面有A,如果使用了aop,就会创建一个aop的动态代理,然后放入到二级缓存中(避免重复创建),如果没有使用aop就直接获取的A的实例。这时候完成了beanB的创建,然后删除B的三级二级缓存,将完整的beanB存入一级缓存中,然后开始继续走beanA的生命流程。

2. sql的联合索引,如果AB两个字段加了索引,那么我select …where B=?;请问用到了索引了么?
答:联合索引中有个最左匹配原则,在AB两列都加了索引的情况下,优先按照A列来进行排序,在A相同的情况下才会对B进行排序,如题中例子,不会用到B的索引;

3. 两表联合查询,left jion … on … ,请问on后面的条件与where后面的条件有什么区别?
答:放在on后面的条件,不管是否为真,都会返回左面表的全部数据,对右表来说,条件为假的时候,左表中会用null来填充;where后面的条件则是生成临时表之后的过滤条件;
4. 线程池,自定义线程池,叙述线程池怎么去执行任务?
答:创建一个自定义的线程池,会有七个参数(**核心线程数,队列,最大线程数,空闲线程存活时间,时间单位,线程工厂,拒绝策略)**当一个任务进来的时候,创建核心线程去处理,当达到核心线程数的时候,再进来任务就会将任务储存在队列中,然后核心线程会来执行队列中的任务,当队列满了之后,再进来任务,就会创建新的线程来处理任务,当线程达到最大线程数之后,再进来任务,就会采取饱和策略;
线程池拒绝策略:
1. AbortPolicy - 抛出异常(线程池默认策略),中止任务。抛出拒绝执行 RejectedExecutionException 异常信息。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行
2. CallerRunsPolicy - 使用调用线程执行任务。当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大
3. DiscardPolicy - 直接丢弃,其他啥都没有
4. DiscardOldestPolicy - 丢弃队列最老任务,添加新任务。当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入
5. redis的作用和运用场景
答:1.用作缓存,减轻数据的压力(注意缓存击穿,缓存穿透,缓存雪崩);
2.做会话存储;
3.实时分析功能,可以做计数器,比如点赞,阅读量等 (利用hyperlog),可以利用zset做 排行榜等
4.可以做分布式锁,在高并发时候,用redis做分布式锁,可以让线程一个一个进来,适用场景秒杀任务时,利用setNX;

6. 怎么做一个秒杀的功能场景?
答:需要做一个秒杀系统,要考虑超买超卖问题,高并发问题,选用redis来实现;
1. 将商品和库存写入到redis中,用户抢购的时候通过redis来进行扣减,再将消息发送到消息队列,由后续服务进行处理
2. 超卖问题:库存数量准确,抢购时先判断库存是否充足,库存大于0在进行扣减,保证两个步骤的原子性。

7. synchronize和lock的区别?
前者是一个java的关键字,而lock是一个接口;前者线程执行完或者发生异常(jvm释放)会主动释放锁资源,而后者需要手动解锁,前者如果获得线程的锁发生阻塞,那么其他线程会一直等待;后者如果发生阻塞,那么其他线程会尝试获取锁资源,不会一直等待
8. 事务失效的场景?
答 :1.在非public修饰的时候;
2.未配置事务管理器;
3.在同一个类中,调用该类的其他事务方法会失效,调用同类方法时候使用的是this去调用,而不是代理对象去调用。解决方案:将被调用方法写入其他类或者在同一个类中注入自己。
9. Springboot的优点?
自动配置和简化配置,内置服务器Tomcat,提供各种stater来方便集成各种中间件,如redis等
10. SpringBoot与spring的区别?
答:1.springboot采用了约定大于配置的这样一个理念,简化了spring的初期搭建,他提供了大量的自动配置,不需要去做大量的xml配置
2.springboot内置有tomcat服务器,项目部署更加方便
3.提供了各种stater来方便集成各种中间件,如redis,mq等。
相比之下,传统spring更加的灵活,可以适用各种复杂项目,但是配置更加复杂,对我来说我更加倾向于springboot,他能让我更加专注于业务代码的开发,不需要花费大量时间来项目搭建和环境配置上。
11. maven的生命周期?
clean-default-site;clean是构建之前清理项目-default是核心部分(编译,测试,打包,部署等)-site是生成站点
12. SpringBoot的自动装配原理?
首先在类启动时候,在@SpringbootApplcation注解里面,有一个@EnableAutoConfiguration:这个注解表明启动自动装配,里面包含两个比较重要的注解@AutoConfigurationPackage和@Import。@import是自动装配的核心,下面有一个selectImport的方法,会去找到MATE-INF/spring.factoriese文件,将里面的jar包全部放在容器中
13. 叙述一下你做过的项目中对你印象最深的项目?
挑一个项目进行解说
14. 分布式系统和微服务系统有什么区别?
分布式:是一个部署方式,将一个系统拆分部署在不同的服务器上,这样来减轻单台服务器的压力,一般有垂直拆分和水平拆分;部署方式一般有集群,主备的方式
微服务:将一个系统拆分成多个服务,这些服务可以单独的运行和部署。服务之间一般基于rpc(远程调用)通信,如dubbo就是一个rpc框架;
15. 说一下什么是双亲委派机制?
在我们创建一个类,类的加载会上报给应用类加载器,然后应用类加载器又上报给扩展类加载器,扩展类加载器会上报给启动类加载器,如果启动类加载器的路径下面没有该类,就会报给扩展类加载器进行加载,扩展类加载器再报给应用类加载器进行加载
16. RPC和HTTP的区别?
答:1.http是一种通信协议,而rpc是一类通信协议的统称(比如RMI协议,dubbo协议等统称为rpc协议)。
2.RPC是一个远程过程调用,主要是用来解决服务与服务之间的一个调用问题,不同服务之间的调用就像同一个服务一样;http使用文本传输协议;

17. 说一说什么是乐观锁与悲观锁
乐观锁就是在线程去更新数据的是时候就会认为数据没有被修改过,然后读取数据和旧数据进行比较,如果有修改,就重新读取数据,在比较然后修改;
悲观锁就在区更新的时候就加锁,只能自己使用,然后直接读取然后修改;

18. mysql的存储引擎有哪些
答:InnoDB是事务型数据库的首选引擎,支持事务安全表(ACID),其它存储引擎都是非事务安全表,支持行锁定和外键,MySQL5.5以后默认使用InnoDB存储引擎。
MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事务,不支持外键。
19. 常见的索引类型有哪些?
位图索引:位图索引适用于字段值为可枚举的有限个数值的情况
哈希索引:哈希索引适用于等值检索,通过一次哈希计算即可定位数据的位置。
Btree索引:有序平衡N叉树, 每个节点有N个键值和N+1个指针, 指向N+1个子节点
倒排索引(也叫反向索引):
20. 行锁和表锁有什么区别?
答:表锁:
一般给表加锁的种类有读锁和写锁;释放锁(unlock)
读锁(lock tables 表名 read):加上该锁,自己和其他线程都不能修改,只能读取
写锁:(lock tables 表名 write):加上该锁之后,只有自己可以读写,其他线程不能进行读写
行锁:正在修改的这行对其他线程不可见,只有提交事物之后才能够看见,并且别的线程不能修改该线程正在操作的行,但是不影响其他线程修改该线程以外的数据。
26.JVM的内存区域划分?
答:JVM区域划分别为:方法区,本地方法栈(线程私有),堆(线程共享),虚拟机栈(线程私有),程序计数器(线程私有)
线程私有:切换线程时候,会恢复到该线程的执行位置;
程序计数器:记录线程的执行位置,每个线程都有自己的程序计数器
本地方法栈:提供给本地方法使用的栈,存储本地方法的一些信息
虚拟机栈:存储一些局部变量
堆:存储是一些new出来的对象
方法区:存储一下静态变量,类属性
27.分布式锁怎么实现?
答:利用setNX来设置key的value,如果当前key不存在则可以设置,证明获得锁,如果设置失败就证明锁已经被使用,当得到锁的线程执行完任务之后就将当前key删除,其他线程就可以获取到锁。需要设置一个超时时间来释放锁。使用expire来设置过期时间。这时候需要开启一个守护线程来给锁续期,如果在29秒的时候还没执行完任务,守护线程就执行expire命令来给锁续期20秒,之后每20秒续期一次。
28.redis是单线程吗?为什么redis那么快?
答:redis是单线程,redis快的原因:
1、完全基于内存的,C语言编写。
2、采用单线程,避免不必要的上下文切换可竞争条件。
3、使用多路I/O复用模型,非阻塞IO。
什么是I/O多路复用:
I/O多路复用是指利用单个线程来同时监听多个Socket ,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。目前的I/O多路复用都是采用的epoll模式实现,它会在通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间,不需要挨个遍历Socket来判断是否就绪,提升了性能。在Redis6.0之后,为了提升更好的性能,在命令回复处理器使用了多线程来处理回复事件,在命令请求处理器中,将命令的转换使用了多线程,增加命令转换速度,在命令执行的时候,依然是单线程。

29.创建线程的方法有哪些?
答:继承thread和实现runnable接口与实现Callable接口或者使用线程池

30.sleep和wait有什么区别?
答:都是让线程阻塞的方法,sleep是线程的静态方法,添加参数可以控制线程睡眠的时间,而wait是Object的方法,需要notify方法来唤醒线程,sleep不会释放锁资源,需要到睡眠时间结束或者通过调用interrupt()方法来唤醒休眠线程;而wait是让当前线程进入等待状态,在别的线程调用notify或者notifyall的时候,会让当前线程进入就绪状态
31.线程的start方法和run方法有什么作用?
答:线程需要调用start方法使线程进入就绪状态,等待CPU调用,而run里面存放的是线程需要执行的逻辑和内容,只有在run方法执行结束或者发生异常之后退出了run方法的时候线程才会被销毁
32.JVM垃圾回收算法?
答:1.标记-清除. 先标记还在使用的对象,将没有被标记的对象清楚,会产生内存碎片
2.标记-复制 将内存分成两部分,每次只使用其中一部分,当这块内存满了之后将还活着的对象复制到另一部分中去,在清楚这部分中的对象。效率高且没有内存碎片,但可用空间少。年轻代中使用的是标记复制。
3.标记-整理 标记活跃对象,全部移到一端,清楚没有被标记的的对象。因为需要移动对象,所以效率比较慢。
4.分代收集算法 将不同生命周期的对象分到不同的区域,使用不同的垃圾回收算法
新生代:使用标记-复制算法,分为dend区和survivor区
老年代:一些生命周期较长的对象,采用标记清除或者标记整理法。
33.arrar和ArrayList有什么区别?
答:array是一个数组,而ArrayList是一个集合;array的长度是固定的,而ArrayList的容量是可以动态增长的,但ArrayList效率没有array高。
34.hashMap是怎么实现的?
答:底层是基于哈希值得数组+链表+红黑树来实现,jdk1.8之后增加了红黑树的数据结构。在链表长度超过8,并且数组长度超过64时候,链表转换成红黑树。
存:put方法的实现,首先将Key和value存到node对象中,然后根据key的hashcode方法计算出key的哈希值,如果该哈希位置上没有链表,那么就会将该key和value存放在这里,如果该位置有链表,那么会调用equals方法如果返回的是true,那么该key-value就会覆盖原本的,如果返回false,那么就会将该key-value加在链表的末端;
取:get方法;首先获取到这个key的哈希值,通过哈希值找到数组下标,如果该处没有链表,那就返回null,如果该处有链表,那么就会将该key去与链表中的key做equals比较,直到返回true时候,就返回value,如果全部都是false,那么也会返回null。
扩容机制:默认长度为16,负载因子是0.75,当每次数组长度达到16*0.75=12的时候会自动扩容,长度变成原来的两倍。
35.runnable和callable的区别?
答:runnable执行不会返回执行结果,因为他只有一个void的run方法。而callable会返回一个执行结果;
Runnable的run方法不能向上抛异常,只能在方法内部消化,而callable的call方法可以向上抛出异常;
36.说一说Spring的aop和ioc?
答:aop是面向切面编程:在不改变原有的逻辑的情况下增加横切面的逻辑,弥补了oop的不足
Ioc是控制反转:是一种思想,不是一个技术,将创建对象的和管理的权利交给spring,存在ioc容器中
DI是依赖注入:三种方式,基于注解注入、构造方法注入和setter注入
Setter注入,就是在实体类中通过set方法来注入,需要set的方法名与xml中的name属性相同;
基于注解注入:@Autowired(自动注入)注解来注入,
构造注入: 如果只有一个有参数的构造方法并且参数类型与注入的bean的类型匹配,那就会注入到该构造方法中。

37.springBoot的核心配置文件有哪些?
答:有Application和bootstarp配置文件;
区别:application主要用于SpringBoot的自动化配置
Bootstarp主要用来加载外部的配置信息,一般用在一些加密解密的场景
38.springBoot的配置文件怎么读取?
答:在springboot启动的时候,通过监听器扫描到配置文件,然后读取。
39.依赖注入的方式有哪些?
答:1.setter注入.
2.构造器注入
3.属性注入(基于注解)
40.@Autowired和@resources有什么区别?
答:@Autowired是属于spring的,而@Resources是属于java的,前者是默认按照类型匹配的,而后者是通过name属性进行匹配的
41.线程的生命周期?
答:新建(new一个线程时候)-就绪(调用了start()方法时候)-运行(被cpu调用之后)-阻塞(同步阻塞、等待阻塞、其他阻塞)-死亡(由于异常或者运行完之后退出run方法,就结束了线程的生命周期)
42.创建bean的方式有哪些?
答:1:调用构造器创建Bean(在实体类中得提供无参的构造函数和set方法,在xml里面指定class属性,提供name属性来进行bean的注入)
2:调用静态工厂方法创建Bean 咱们把创建Bean的任务交给了静态工厂,而不是构造函数
3:调用实例工厂方法创建Bean 意思是先实例化工厂 再生产

43.怎么获取到配置文件中的某个值?
答:创建ResourceClasspath对象,传入配置文件的路径,使用io来获取;
44.spring创建的bean是线程安全的吗?
答:spring 管理的 bean 的线程安全跟 bean 的创建作用域和 bean 所在的使用环境是否存在竞态条件有关,spring 并不能保证 bean 的线程安全。
1.如果是prototype(多例Bean),每次都会创建一个新的对象,没有共享bean。就不存在线程安全的问题。
2.如果是ingleton(单例Bean),只存在一个全局共享的实例,可能会存在线程安全的问题。单例bean分为有状态bean(如果会进行更新操作,可能会存在线程安全的问题)和无状态bean(多线程操作中,只会进行查询,不会进行修改)不存在线程安全问题。
如何处理有状态bean的线程安全问题:
1. 将 “singleton” 改为 “prototype”
2. 避免定义可变的成员变量
3. 在类中定义ThreadLocal的成员变量,并将需要的可变成员变量,保存在ThreadLocal中, ThreadLocal本身具备线程隔离的特性,这就相当于为每个线程提供了一个独立的变量副本,每个线程只需要操作自己的线程变量副本,从而解决线程安全问题。
45.什么叫做索引失效?
答:1.有or必全有索引;
2.复合索引未用左列字段;
3.like以%开头;
4.需要类型转换;
5.where中索引列有运算;
6.where中索引列使用了函数;
7.如果mysql觉得全表扫描更快时(数据少);
46.b树索引和哈希索引有什么区别?
答:哈希索引只适用于=和in的判断,
索引的种类:
普通索引:仅加速查询
唯一索引:加速查询 + 列值唯一(可以有null)
主键索引:加速查询 + 列值唯一(不可以有null)
表中只有一个组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
全文索引:对文本的内容进行分词,进行搜索
ps.
索引合并,使用多个单列索引组合搜索
覆盖索引,select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖
47.数据库出现死锁怎么解决?
答:产生死锁的原因:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
解除死锁和预防死锁:
预防:(1)按同一顺序访问对象。
(2)避免事务中的用户交互。
(3)保持事务简短并在一个批处理中。
(4)使用低隔离级别。
(5)使用绑定连接。
解除:在操作多表时候,保证同时锁定多表,加更新锁(“我现在只想读,你们别人也可以读,但我将来可能会做更新操作,我已经获取了从共享锁(用来读)到排他锁(用来更新)的资格”。一个事物只能有一个更新锁获此资格),SQL语句中不要使用太复杂的关联多表的查询;使用“执行计划”对SQL语句进行分析,对于有全表扫描的SQL语句,建立相应的索引进行优化
48.修改equals需要重写hashcode吗?
答:需要,如果两个对象的equals相等,那么他们的hashcode一定相等,如果我们重写了equals方法,而不重写hashcode方法,那么就不满足这一条。
50.JVM这样确定一个对象是否可以被回收?
答:1.可达性分析. 通过一系列的GC Roots的对象作为起点,从这些节点开始向下搜索,当一个对象没有与如何节点相连时候,就可以被回收。
2.引用计数法. 给对象添加一个引用计数器,每次被调用计数器就+1,当引用失效就-1.任何时候只要计数器为零的时候,该对象就可以被回收。
51.事务传播机制有哪些?
答:1.REQUIRED(Spring默认的事务传播类型 ):如果当前没有事务,则自己新建一个事务,如果当前存在事务则加入这个事务
解释:当A调用B的时候:如果A中没有事务,B中有事务,那么B会新建一个事务;如果A中也有事务、B中也有事务,那么B会加入到A中去,变成一个事务,这时,要么都成功,要么都失败。
2.SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
解释:如果A中有事务,则B方法的事务加入A事务中,成为一个事务,如果A中没有事务,那么B就以非事务方式运行(就是普通的方法调用);

3.MANDATORY :当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。
如果A中有事务,则B方法的事务加入A事务中;如果A中没有事务,B中有事务,那么B就直接抛异常
4.REQUIRES_NEW:新建一个事务,如果存在当前事务,则挂起该事务。
B会新建一个事务,A和B事务互不干扰,他们出现问题回滚的时候,也都只回滚自己的事务;
5.NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务
被调用者B会以非事务方式运行,如果A中有事务,A会被挂起不执行,等待B执行完结束;A出现异常会回滚,但B已经提交不会回滚。

6.NEVER: 如果当前没有事务存在,就以非事务方式执行;如果有,就抛出异常。
A中有事务,去调用B,直接跑异常。

7.NESTED 嵌套事务:如果当前事务存在,则在嵌套事务中执行,否则开启一个事务。
如果A中没有事务,那么B创建一个事务执行,如果A中也有事务,那么B会会把事务嵌套在里面。
52.字符串拼接+与append()的区别?
答:使用str1+str2的时候会先new StringBuilder()创建一个StringBuilder对象,然后再调用StringBuilder.append()方法来拼接字符串将str1然后在拼接str2,然后在调用toString()方法返回字符串(创建了一个String对象)。所以每使用一次+都会创建一个StringBuilder对象和三个String对象。
53.redis缓存出现的问题?
答:缓存击穿:一个key失效,大量的请求进来访问这个key,然后就会直接访问到数据库;
解决方案: 1.延长过期时间,或者设置为永不过期。
2.使用互斥锁,在第一个请求进来的时候,加上锁,直到这个请求查询完数据库之后,把数据写入缓存中之后再释放锁。
缓存穿透:请求来查询缓存,缓存中没有该数据,这个请求去查询数据库,数据库中也没有该数据。
解决方案:1.对请求进行过滤,比如一些id<0等的请求。
2.设置null值,查询数据库中没有该数据的时候,缓存中存一个null。
3.使用布隆过滤器,查询过的key就不让查询
布隆过滤器的缺点:删除困难,存在误判(可以创建一个白名单,存储可能存在误判的数据)。

缓存雪崩:大量的key失效,导致大量请求跑到数据库。
解决方案:1.部署缓存集群
2.分开设置过期时间,不让大量数据同时过期
JVM调优如何做?
答:1.选择合适的垃圾回收器
2.设定日志参数:-Xloggc:/path/name-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogs=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCauses
3.合理规划内存
threadLocal是什么?
答:线程隔离,threadLocal是Java中提供的线程本地储存机制,底层是threadLocalMap实现的,每个Thread对象都有一个ThreadLocalMap。实际上就是用来操作Thread的TthreadLocalMap的一个类。如果在线程池当中使用threadLocal会造成内存泄漏,需要手动调用ThreadLocal的remove方法,手动清楚entry对象。

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值