2020 面试题 新鲜出炉 --持续更新

更多好文,请关注微信公众号 Java书友会

写在前面

所谓金三银四,我的书友朋友们最近又分享了很多面试题,特地总结分享一波。在开始之前呢,我有必要废话几句。在日常的工作当中,可能我们大多数人还是以业务为主,然而在面试官的眼里,你项目中所有涉及的技术栈,你都要掌握其原理。这对于接触边边角角的你来说着实不容易。在工作之外,你可能也学习了很多技术栈,但是大多数时候却只仅限于理论,缺少实战场景,可能过一段时间也就忘记了。究其原因的话,就是java生态目前知识体系太过于庞大。想要面面俱到,非一日之功可以完成。必须沉下心来一个知识点一个知识点去进行攻克。而以下的面试题,会持续更新实现全覆盖。我尽可能以自己所理解的大白话对白的形式去回答这些面试问题。但这并不意味着你背过了这些题,就可以面试高枕无忧,而是要透过这些题,去梳理自己的知识树。按照自己的语言形式和思考方式,将这些知识点内化成自己的东西,才是你最终的目标。好了,废话不多说,正文开始。

正文开始

1、自定义注解如何实现?

嗯,我拿工作当中的一个例子来说明吧,就是我们工作中会有一些系统日志的场景,就是自定义注解来实现的。
我们自定义这个注解的话,用@interface来声明一个类Syslog,同时加上元注解@Retention(RetentionPolicy.RUNTIME), 用来标明自定义的注解可以保留到运行期。此外还要加上@Target(ElementType.METHOD)元注解,标明改自定义注解是被使用方法上。这样的话,便实现了一个自定义注解。除此之外,我们也可以引入@Inherited元注解,这样定义的注解是可以被继承的,就是说一个父类给这样自定义的注解修饰的话,那么他的子类也默认被该注解修饰。

2、自定义你是如何使用的,或者说你使用他 是如何生效的?

还是拿刚才说的那个自定义系统日志来说明吧。我们是通过Spring AOP切面织入的方式去是这个自定义注解生效的。通过Spring 自身的@Aspect

3、spring 如何创建bean?

嗯,Spring创建Bean一般有三种方式,分别是利用构造器创建,静态工厂创建,实例工厂方法创建,都需要配置相应的xml文件。交给Spring去解析创建。

4、spring bean的生命周期?
Spring生命周期主要分为四个阶段:初始化 属性赋值 实例化 销毁。具体的过程呢,就是Spring会在项目启动时加载配置文件,将文件中的类信息封装为BeanDefination。核心的步骤就是通过反射的方式去给类名称去赋值 并且创建实例,然后会添加到IOC容器中。销毁的话就是将beanWapper对象从容器中去除。
5、juc包下有哪些类?

juc:java Util Concurrent包,主要有原子类、锁、还有队列、线程池、并发集合等。

6、线程池的核心参数?

线程池的核心参数有:核心线程数、最大线程数、存活时间、队列、拒绝策略。

7、线程池队列的作用?

主要目的在于,等待核心线程数执行完,提高线程的可复用性。刚才我们提到了线程池的几个核心参数。当用户线程进入线程池后,会先查看核心线程数有没有用完,如果没有,则创建线程;如果有,则加入的阻塞队列。持续不断的线程进来,会继续看阻塞队列是否已满,未满 则会继续创建线程进行执行。如果已满,则会去执查看最大线程数是否有剩余,有的话,继续创建线程进行执行。如有没有,则去执行拒绝策略。

8、你们工作中是怎么使用线程池的?

在日常开发项目中,我们有大量的业务场景使用到了线程池。例如:图书终审,图书听书定时上架,之前很早做的集团用户导入等业务场景。针对项目中大量是用的线程池场景,我们有封装了一个线程池管理类,来保证不同的线程池是单例的,并且给了兜底的线程池配置。不同的任务也可以自己配置相应的参数。然后创建不同的线程任务,扔给这个线程池管理去执行execute()方法。

9、线程池的execute()方法和submit()方法的区别?

我们都知道,线程池的execute()方法是开启线程池中的任务。线程池的submit()方法同样可以做到,但是submit()方法执行相应的任务之后可以返回执行结果Future对象。如此一来,submit()方法可以判断线程池中的任务什么时候完成或者是捕获线程池执行中的异常。通常使用在我们需要知道线程池执行结果的场景。看过线程池这两个方法的源码,我们可以发现,submit()方式是对execute()方法的一个封装,将传入的任务通过RunnableFuture对象进行了封装,实际上还是调用了execute()方法。

说说对nio的理解?谈谈你对docker的理解?docker的常用命令?k8s的作用?类加载机制?分布式锁有哪些实现方式?zk是如何实现分布式锁的?mysql的索引是否生效如何查看?redis的默认端口?redis哈希槽的实现?工作中遇到什么问题,怎么解决的?

说说RPC框架dubbo的执行原理?

谈谈sql优化?

随着项目业务数据量增大的情况,sql的执行效率则会影响程序的运行。那么怎么优化呢?
1、对于查询语句来说,要尽可能避免全面扫描,对于模糊查询的字段和排序的字段优先建立索引。
2、避免where子句使用null进行判断,否则会走全表扫描,可以给予默认值。
3、避免where子句中使用不等于 (!=或者<>)操作符,如此操作也会引起全表扫描。
4、避免where子句使用or进行查询,可以使用union all 进行代替。
5、慎用in或者not in,也会导致全表扫描,连续数据可以采用 between and
6、禁用全模糊查询,而采用右模糊查询,如此可以走索引。而左模糊是不能走索引的。至于为什么呢?因为我们的索引是一棵B+树,从左到右查询是有序的。所以只有在左侧是定值的时候,才能去确定索引。下面这种情况,却会是走到索引的。
例如where子句: where a = '1' and  b like '%2' (a,b)建立联合索引。这种情况就属于索引下推了。
7、避免where子句进行表达式操作(例如加减乘除),该操作会导致数据库放弃索引。
8、避免where子句进行函数操作,该操作会引起全表扫描。
9、使用复合索引时,应该满足最左优先原则,使得用到左边的字段,并且尽可能保证索引字段和查询条件顺序一致。
10、使用exists 代替in进行查询。例如:
select num from a where num in(select num from b)    
用下面的语句替换:    
select num from a where exists(select 1 from b where num=a.num)  
11、对于有大量重复数据的字段来说,建立了索引也无法生效。如果非要这么做,建议使用该字段和其他字段作为组合索引。
12、索引并不是越多越好,在提升出了查询效率的同时,会降低insert及update效率,因为在执行新增或者更新的时候有可能会重建索引。同时,一张表的索引最多不要超过6个,太多的话,可以去掉一些不常用的字段索引。

缓存击穿和缓存雪崩的区别?

在这里插入代码片

缓存雪崩如何避免?

如何避免消息重复消费?

如何解决消息堆积的问题?

如何解决消息丢失问题?

redis的双写一致性如何实现?

分布式锁?

说说JVM的内存模型?

new一个对象之后,他在内存中的过程描述下?

说说你对CAP理论的理解?

嗯,CAP理论是指在分布式系统当中,一致性(C-Consistency),可用性(A-Availability),分区容错性(Partition torlerance),这三者最多只能同时满足两点,不可能是三者同时满足。

说说AOP与AspectJ的区别?

AspectJ和Spring AOP都是对目标类增强,生成代理类。
AspectJ是在编译期间将切面代码编译到目标代码的,属于静态代理;Spring AOP是在运行期间通过代理生成目标类,属于动态代理。
AspectJ是静态代理,故而能够切入final修饰的类,abstract修饰的类;Spring AOP是动态代理,其实现原理是通过CGLIB生成一个继承了目标类(委托类)的代理类,因此,final修饰的类不能被代理,同样staticfinal修饰的方法也不会代理,因为staticfinal方法是不能被覆盖的。在CGLIB底层,其实是借助了ASM这个非常强大的Java字节码生成框架。关于CGLB和ASM的讨论将会新开一个篇幅探讨。
Spring AOP支持注解,在使用@Aspect注解创建和配置切面时将更加方便。而使用AspectJ,需要通过.aj文件来创建切面,并且需要使用ajc(Aspect编译器)来编译代码;

Spring AOP我们可以使用Aspectj提供的注解;换句话说就是使用Aspectj的语法风格,所以你在做springAop的时候@Aspect@Before@PonitCut等等这些注解其实都是Aspectj提供的,不是spring提供的

猜你喜欢

转载自blog.csdn.net/aiwaston/article/details/105064345