java面试题 - Go语言中文社区

java面试题


mysql db cpu过高的情况
跨域原理及解决办法
session 与 cookie
@RequestParam和@RequestBody的区别

Redis、MongoDB及Memcached的区别

理解java类加载器以及ClassLoader类

组合索引的使用

JVM调优总结 -Xms -Xmx -Xmn -Xss

mybatis 加载原理 底层实现 一级缓存和二级缓存
springboot 和springmvc比较的优势
springcloud 相关组件介绍

Redis数据过期策略详解

线上服务CPU100%问题快速定位实战

什么是springboot
用来简化spring应用的初始搭建以及开发过程 使用特定的方式来进行配置(properties或yml文件)
创建独立的spring引用程序 main方法运行
嵌入的Tomcat 无需部署war文件
简化maven配置
自动配置spring添加对应功能starter自动化配置
springboot常用的starter有哪些
spring-boot-starter-web 嵌入tomcat和web开发需要servlet与jsp支持
spring-boot-starter-data-jpa 数据库支持
spring-boot-starter-data-redis redis数据库支持
spring-boot-starter-data-solr solr支持
mybatis-spring-boot-starter 第三方的mybatis集成starter
springboot自动配置的原理
在spring程序main方法中 添加@SpringBootApplication或者@EnableAutoConfiguration会自动去maven中读取每个starter中的spring.factories文件 该文件里配置了所有需要被创建spring容器中的bean

springboot读取配置文件的方式
springboot默认读取配置文件为application.properties或者是application.yml
springboot集成mybatis的过程
添加mybatis的starter maven依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
在mybatis的接口中 添加@Mapper注解
在application.yml配置数据源信息
springboot如何添加【修改代码】自动重启功能
添加开发者工具集=====spring-boot-devtools
什么是微服务
以前的模式是所有的代码在同一个工程中部署在同一个服务器中同一个项目的不同模块不同功能互相抢占资源
微服务将工程根据不同的业务规则拆分成微服务 微服务部署在不同的机器上 服务之间进行相互调用Java微服务的框架有 dubbo(只能用来做微服务),spring cloud(提供了服务的发现,断路器等)
springcloud如何实现服务的注册和发现
服务在发布时 指定对应的服务名(服务名包括了IP地址和端口) 将服务注册到注册中心(eureka或者zookeeper)这一过程是springcloud自动实现 只需要在main方法添加@EnableDisscoveryClient 同一个服务修改端口就可以启动多个实例
调用方法:传递服务名称通过注册中心获取所有的可用实例 通过负载均衡策略调用(ribbon和feign)对应的服务

ribbon和feign区别
Ribbon添加maven依赖 spring-starter-ribbon 使用@RibbonClient(value="服务名称") 使用RestTemplate调用远程服务对应的方法
feign添加maven依赖 spring-starter-feign 服务提供方提供对外接口 调用方使用 在接口上使用@FeignClient("指定服务名")
Ribbon和Feign的区别:
Ribbon和Feign都是用于调用其他服务的,不过方式不同。
1.启动类使用的注解不同,Ribbon用的是个@RibbonClient,Feign用的是@EnableFeignClients。
2.服务的指定位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
3.调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。
Feign则是在Ribbon的基础上进行了一次改进,采用接口的方式,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建http请求。不过要注意的是抽象方法的注解、方法签名要和提供服务的方法完全一致。
springcloud断路器的作用
当一个服务调用另一个服务由于网络原因或者自身原因出现问题时 调用者就会等待被调用者的响应 当更多的服务请求到这些资源时导致更多的请求等待 这样就会发生连锁效应(雪崩效应) 断路器就是解决这一问题断路器有完全打开状态一定时间内 达到一定的次数无法调用 并且多次检测没有恢复的迹象 断路器完全打开,那么下次请求就不会请求到该服务半开短时间内 有恢复迹象 断路器会将部分请求发给该服务 当能正常调用时 断路器关闭 关闭当服务一直处于正常状态 能正常调用 断路器关闭

实现短连接算法
500万用户文件,包含userid,age字段,一个2亿的用户记录文件, 先按年龄段过滤并且按用户记录排序

查询各课程的平均成绩并按成绩降序排列
select 科目 ,avg(成绩) from 课程
group by 科目
order by agv(成绩)
一、语句为:
SELECT S.学号,姓名,AVG(成绩)平均成绩 FROM S,SC
WHERE S.学号=SC.学号
GROUP BY S.学号 HAVING COUNT(*)>5 ORDER BY 3 DESC

二、注意要点:
1)题目要求查询平均成绩,表中不存在“平均成绩”字段,需要使用VAG函数。
2)学生表student和成绩表score都含有“学号”字段,在查询时需指明学号属于哪个表。
3)GROUP BY短语对于查询结果进行分组,后跟随HAVING短语来限定分组必须满足查询选修课在5门以上的学生,必须在分组后再统计,所以CONM(大)>S应在HAVING后。



分库分表策略,常见的策略有
取模(库ID 按主键 或hash字符串主键 % 库数量 表ID 主键或hash字符串主键/库数量%表数量)、分区(可按照时间分区、范围分区,时间分区规则如一个月一个表、一年一个库。范围分区规则如0~2000万一个表,2000~4000万一个表。如果分区规则很复杂,则可以有一个路由表来存储分库分表规则。分区的缺点是存在热点,但是易于水平扩展,能避免数据迁移。)、路由表等。

synchronized与Lock的区别
类别
synchronized
Lock
存在层次
Java的关键字,在jvm层面上
是一个类
锁的释放
1、以获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁
在finally中必须释放锁,不然容易造成线程死锁
锁的获取
假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待
分情况而定,Lock有多个锁获取的方式,具体下面会说道,大致就是可以尝试获得锁,线程可以不用一直等待
锁状态
无法判断
可以判断
锁类型
可重入 不可中断 非公平
可重入 可判断 可公平(两者皆可)
性能
少量同步
大量同步

为什么使用B+树?言简意赅,就是因为:
1.文件很大,不可能全部存储在内存中,故要存储到磁盘上
2.索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数(为什么使用B-/+Tree,还跟磁盘存取原理有关。)
3.局部性原理与磁盘预读,预读的长度一般为页(page)的整倍数,(在许多操作系统中,页得大小通常为4k)
4.数据库系统巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入,(由于节点中有两个数组,所以地址连续)。而红黑树这种结构,h明显要深的多。由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性

数据库连接池有很多实现,如C3P0、DBCP、Druid等。
工厂模式一般分为3种:简单工厂、工厂、抽象工厂。
一、三种工厂的实现是越来越复杂的
二、简单工厂通过构造时传入的标识来生产产品,不同产品都在同一个工厂中生产,这种判断会随着产品的增加而增加,给扩展和维护带来麻烦
三、工厂模式无法解决产品族和产品等级结构的问题
四、抽象工厂模式中,一个工厂生产多个产品,它们是一个产品族,不同的产品族的产品派生于不同的抽象产品(或产品接口)。
1、在上面的代码中,都使用了接口来表达抽象工厂或者抽象产品,那么可以用抽象类吗?有何区别?
从功能上说,完全可以,甚至可以用接口来定义行为,用抽象类来抽象属性。抽象类更加偏向于属性的抽象,而用接口更加偏向行为的规范与统一。使用接口有更好的可扩展性和可维护性,更加灵活实现松散耦合,所以编程原则中有一条是针对接口编程而不是针对类编程。
2. 到底何时应该用工厂模式
根据具体业务需求。不要认为简单工厂是用switch case就觉得一无是处,也不要觉得抽象工厂比较高大上就到处套。我们使用设计模式是为了解决问题而不是炫技,所以根据三种工厂模式的特质,以及对未来扩展的预期,来确定使用哪种工厂模式。
3.说说你在项目中工厂模式的应用
如果你看了这篇文章,被问到这个问题时,还傻乎乎的去举数据库连接的例子,是要被打板子的。。。比如我之前做过一个旅游产品的B2B网站,根据不同类型的业务形态,产品也是不同的,有国内跟团,出境跟团,国内自由行,出境自由行,邮轮五种产品,并且后面可能还会有门票,酒店,机票等等产品,其中有些联系也有些区别。
所以在面试中,我完全把工厂模式和我做的东西联系起来,如何建立工厂,如何生产不同的产品,如何扩展,如何维护等等。我想,把理论应用到实际,而且是真实业务逻辑中,给面试官的印象无论如何不会太差,甚至会对你刮目相看。
当然,即便是你没有真的使用过,如果面试官问道了工厂模式,你仍然可以把你以往的经验和设计模式联系起来回(hu)答(you)面试官,只要你理解了,把来龙去脉说清楚,并且可以回答问题,我想应该是可以令面试官满意的。
代理模式:
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.

订单失效处理方案:
2、延迟队列
延迟队列让您可以将队列中新消息的传递操作推迟指定的毫秒数
byte[] messageBodyBytes = "delayed payload".getBytes("UTF-8");Map<String, Object> headers = new HashMap<String, Object>();headers.put("x-delay", 5000);AMQP.BasicProperties.Builder props = new AMQP.BasicProperties.Builder().headers(headers);channel.basicPublish("my-exchange", "", props.build(), messageBodyBytes);
如上会将消息推迟5000毫秒才会推送给消费者.
优点:1、消息传输可靠 2、延迟小 3、开源免费 4、高可用
同一张表同样的SQL 一个走索引,一个不走
select count(id) from st_alldata_m m left join a_stbprp where paratype='0001'
paraid 有索引 ,
如果条件是 paratype=‘0001’ 不走索引;
条件是 paratype=‘0004’ 就走索引;
求指教啊
paratype 没有空值

可能是优化器在查询'0001'值时,判断全表扫描快于索引,要看你的索引选择度是否高
也可能是该表经常增删改,产生过多索引碎片,导致索引失效
前一种就是系统合理判断(也有可能是统计信息采集出错),
后一种需要重建或重组索引


JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
简单的实现举例:
这是一个需要被代理的类,也就是父类,通过字节码技术创建这个类的子类,实现动态代理。
public class SayHello {
public void say(){
System.out.println("hello everyone");
}
}
该类实现了创建子类的方法与代理的方法。getProxy(SuperClass.class)方法通过入参即父类的字节码,通过扩展父类的class来创建代理对象。intercept()方法拦截所有目标类方法的调用,obj表示目标类的实例,method为目标类方法的反射对象,args为方法的动态入参,proxy为代理类实例。proxy.invokeSuper(obj, args)通过代理类调用父类中的方法。
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
//实现MethodInterceptor接口方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("前置代理");
//通过代理类调用父类中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置代理");
return result;
}
}
具体实现类:
public class DoCGLib {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//通过生成子类的方式创建代理类
SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);
proxyImp.say();
}
}
输出结果:
前置代理
hello everyone
后置代理
JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,这就是为什么采用动态代理时为什么只能用接口引用指向代理,而不能用传入的类引用执行动态类。
CGLib采用的是用创建一个继承实现类的子类,用asm库动态修改子类的代码来实现的,所以可以用传入的类引用执行代理类
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理


Integer a = 1 Integer b = 1 a==b -> true Integer a = 1111 Integer b = 1111 a==b -> false 求解释啊。
在自动装箱时对于值从–128到127之间的值,它们被装箱为Integer对象后,会存在内存中被重用,因为是重用,所以 Integer b = 1,实际上并没有重新生成对象,而是引用了Integer a对象
实际上参考的是同一个对象。内存地址一样,所以结果是true,如果你是这样写
Integer a= new Integer(1);
Integer b = new Integer(1);
那么结果就会是false了,应该他确实重新生成对象了
如果超过了从–128到127之间的值,被装箱后的Integer对象并不会被重用,
即相当于每次装箱时都新建一个 Integer对象,所以Integer a = 1111 Integer b = 1111参考的是不同的对象。内存地址不同,结果是false,对象如果要比较值,应该用.equals()方法



java语言支持的变量类型
类变量:独立于方法之外的变量,用 static 修饰。
局部变量:类的方法中的变量。
实例变量(全局变量):独立于方法之外的变量,不过没有 static 修饰。
实例变量非线程安全
ArrayList和LinkedList的大致区别如下:
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
分布式锁同时去创建顺序子节点并watch 拥有最小序号的持有锁 当释放锁,所有人被通知,再次检测自己是否是最小

水平分表:每个字表的字段都一样,目的:解决单表容量不足(1000w);垂直分表:每个字表的字段不一样,目的:避免单表单行太大,引起分页存储。用uuid做主键,由于不是业务相关,分库分表(散列 连续)需要业务主键做路由。
spring starter的工作原理 springboot在启动时扫描所依赖的jar包,寻找包含spring.factories文件的jar包根据spring.factories配置加载AutoConfigure类根据@Conditional注解的条件,进行自动配置并将Bean注入Spring Context。
zk和eureka区别:zk主要是保证数据一致性,eureka保证可用性。eureka还提供了自我保护等机制。
spring如何解决循环依赖的?
rocketmq消费者发生异常怎么办?消息是如何落地的?
nignx负载均衡策略有哪些?
spring容器初始化过程是怎样的?
线程池的参数最大线程数是做什么的,如果超过了会有什么问题?
mybatis的#和$有什么区别?
将一个链表排序

有一个生成唯一串的需求,并发请求量非常大,该如何实现?
ip+进程号+当前时间(精确到纳秒)+计数器(每次批量生成串的时候重置计数器为0),由定时检查队列的线程批量生成后放到队列(可以采用LinkedBlockingQueue )中,一秒种检查一次队列中的串数量,队列大小可以设置为指定的数量,当队列中的串数量低于多少时,往队列中追加新生成的串。获取串的线程访问由队列控制即可。
思路:
1、生成串由单线程批量生成。
2、并发获取的线程由队列(队列采用链表的阻塞队列实现)进行控制。
串的生成格式:ip+进程号+当前时间(精确到纳秒)+计数器(每次批量生成串的时候重置计数器为0)
可以解决,多机多JVM实例的问题,计数器可以解决时间相同的问题

spring 加载过程 注解
springmvc加载过程 注解 参数区别
servlet是不是线程安全的 在什么场景下安全 什么场景下不安全
redis nginx 线程模型
mycat分库分表处理
volital 使用场景
OOM错误,stackoverflow错误,permgen space错误
如果线程请求的栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
一个对象jvm过程
触发JVM进行Full GC的情况及应对策略
1、System.gc()方法的调用
此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。
2、老年代代空间不足
老年代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出如下错误:
java.lang.OutOfMemoryError: Java heap space
为避免以上两种状况引起的Full GC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。
3、永生区空间不足
JVM规范中运行时数据区域中的方法区,在HotSpot虚拟机中又被习惯称为永生代或者永生区,Permanet Generation中存放的为一些class的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下也会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出如下错误信息:
java.lang.OutOfMemoryError: PermGen space
为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。
4、CMS GC时出现promotion failed和concurrent mode failure
对于采用CMS进行老年代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能
会触发Full GC。promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入老年代,而此时老年代也放不下造成的;concurrent mode failure是在
执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足造成的(有时候“空间不足”是CMS GC时当前的浮动垃圾过多导致暂时性的空间不足触发Full GC)。
对措施为:增大survivor space、老年代空间或调低触发并发GC的比率,但在JDK 5.0+、6.0+的版本中有可能会由于JDK的bug29导致CMS在remark完毕
后很久才触发sweeping动作。对于这种状况,可通过设置-XX: CMSMaxAbortablePrecleanTime=5(单位为ms)来避免。
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_40309277/article/details/80164571
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-07 03:22:34
  • 阅读 ( 1252 )
  • 分类:面试题

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢