一面
1、自我介绍、自己做的项目和技术领域
2、项目中的监控:那个监控指标常见的哪些?
3、微服务涉及到的技术以及需要注意的问题有哪些?
4、注册中心你了解了哪些?
Zookeeper:历史悠久,数据存储格式类似文件系统,通过私有协议访问,集群式架构。优点是成熟稳定,缺点是系统复杂,资源占用高
Consul:Consul 提供了高可用的kv存储,集群架构,这点和etcd zookeeper类似。 另外也提供了自动服务发现注册的套件,并且能否对服务进行健康检查。 结合consul-template可以实现服务提供方信息更新(比如增加了API服务器)时,自动生成配置文件给服务使用方自动更新配置。
Consul支持跨数据中心
Eureka
5、consul 的可靠性你了解吗?
6、consul 的机制你有没有具体深入过?有没有和其他的注册中心对比过?
7、项目用 Spring 比较多,有没有了解 Spring 的原理?AOP 和 IOC 的原理
Spring的两个核心概念是IOC(控制反转)和AOP(面向切面编程).
IOC: IOC(控制翻转)是一种编程范式,可以在一定程度上解决复杂系统对象耦合度太高的问题,并不是Spring的专利。IOC最常见的方式是DI(依赖注入),可以通过一个容器,将Bean维护起来,方便在其他地方直接使用,而不是重新new。可以说,IOC是Spring最基本的概念,没有IOC就没有Spring。
为什么DI可以起到解耦的作用?
一个软件系统包含了大量的对象,每个对象之间都有依赖关系,在普通的软件编写过程中,对象的定义分布在各个文件之中,对象之间的依赖,只能通过类的构造器传参,方法传参的形式来完成。当工程变大之后,复杂的逻辑会让对象之间的依赖梳理变得异常困难。
beans包实现的核心关注点是BeanFactory,BeanFactory也叫作Bean容器,顾名思义,是用来盛放、管理bean的。
context包实现的核心关注是ApplicationContext,ApplicationContext也是用来获取Bean的,但是它更高层,它的面向用户是Spring的使用者,而BeanFactory面向的用户更多是Spring开发者。BeanFactory定义了Bean初始化的流程,ApplicationContext定义了从XML读取,到Bean初始化,再到使用的过程。
AOP:Spring内部的声明式事务和拦截器都是利用了AOP的强大威力,才得以优雅的实现。
它可以让编程人员在不修改对象代码的情况下,为这个对象添加额外的功能或者限制。
很熟悉吧,这就是代理模式!
因为AOP涉及的知识较为复杂,所以我先将背景知识介绍一下。
Java动态代理,就是Java本身提供的代理实现,要求对象必须实现某一个接口。
CGLib库,为Java提供了,为普通类提供代理的功能。
aspectj包,实现了,通过一种固定的编程语言,通过这种简单的编程语言,我们可以定位到被代理的类,自动完成代理。
Spring AOP之所以能够为动态生成的Bean提供代理,得益于PostProcessor接口。我们会议IOC初始化流程中,最后一部,就是得到BeanFactory之中所有继承了PostProcessor接口的bean,调用它们的postProcessBeforeInitilization、postProcessAfterInitilization方法,来代理bean,生成新的bean。
在这里,我们的对象是AspectJAwareAdvisorAutoProxyCreator。
在这个对象的方法中,逻辑是这样的,找到xml里面所有切面bean,然后在这些bean里面,找到符合被代理类的切面bean,找到切面bean之后,就可以获得增强,切点等,于是可有构造一个AdvisorSupport,知道了AdvisorSupport,我们就能够通过proxyFactory来获取代理了。
至于如何这个类切面是用来切入代理类的,这个就要交给PointCut来实现了,pointcut有很多实现方式,这里我们用的是aspectj。具体这个类我就不细讲了。
ApplicationContext-用户与BeanFactory之间的桥梁
beans.context包有三个类、接口,完成了ApplicationContext的基本功能。
- ApplicationContext接口,没有任何方法,只是继承了BeanFactory接口,暗示ApplicationContext与BeanFactory都是获取Bean的地方。
- AbstractApplicationContext抽象类,首先,它的构造函数接收入参BeanFactory,所以说ApplicationContext内部具有一个BeanFactory。类似于一种装饰器模式,但不是装饰器模式,类似于代理模式,但也不是代理模式。fresh方法分为三个步骤:1.loadBeanDefinitions,这个是一个模板方法,需要子类实现,它的作用就是从某一个地方读取BeanDefinition,然后写入到ApplicationContext自己的BeanFactory里面,这就是ApplicationContext与BeanFactory之间的联系,也就是ApplicationContext还负责了读取定义。2. registerBeanPostProcessors,这个就是在BeanFactory里面找到BeanPostProcessor,然后将他们放到BeanFactory的beanPostProcessors容器里面,方便BeanFactory初始化使用。3. onRefresh初始化一遍所有的bean。
ClassPathXmlApplicationContext实现了loadBeanDefinitions的方法,将xml文件和BeanFactory结合在一起。
Spring Aop 中 Jdk 动态代理就是利用代理模式技术实现的
8、Spring Boot除了自动配置,相比传统的 Spring 有什么其他的区别?
- Spring Boot可以建立独立的Spring应用程序;
- 内嵌了如Tomcat,Jetty和Undertow这样的容器,也就是说可以直接跑起来,用不着再做部署工作了。
- 无需再像Spring那样搞一堆繁琐的xml文件的配置;
- 可以自动配置Spring;
- 提供了一些现有的功能,如量度工具,表单数据验证以及一些外部配置这样的一些第三方功能;
- 提供的POM可以简化Maven的配置;
9、Spring Cloud 有了解多少?
10、Spring Bean 的生命周期
- getBean, 在beanDefinitionMap里面得到bean,如果没有的话,先初始化。(为什么会没有,因为ApplicationContext读取xml文件时候,只是给BeanDefinition服了类类型,并没有赋值对象,这个对象还是需要BeanFactory通过反射生成的)。
- createBeanInstance,通过反射,根据BeanDefinition的类对象新建实体对象->将得到的bean对象赋值给beandefinition,然后将BeanDefinition里面的属性都注入到Bean里面,这就完成了doCreateBean。
- initializeBean就是调用BeanPostProcessor的postProcessBeforeInitilizztion方法和postProcessAfterIntilizatin方法,获取新的bean,这里会在aop中用到。
11、HashMap 和 hashTable 区别?
12、Object 的 hashcode 方法重写了,equals 方法要不要改?
在我们的业务系统中判断对象时有时候需要的不是一种严格意义上的相等,而是一种业务上的对象相等。在这种情况下,原生的equals方法就不能满足我们的需求了
所以这个时候我们需要重写equals方法,来满足我们的业务系统上的需求,重写hashCode只是技术要求(为了提高效率)为什么要重写equals呢?因为在java的集合框架中,是通过equals来判断两个对象是否相等的
Hash碰撞:通过合理的利用各个属性对象的散列码进行组合,使得hash更加均匀,或者增加hash桶的大小
13、Hashmap 线程不安全的出现场景
14、线上服务 CPU 很高该怎么做?有哪些措施可以找到问题
- 检查是否有死循环。
- 频繁的GC.或者有大量的线程。
- 算法太复杂或者太多
- 数据库连接的资源未释放或未关闭,
数据库connection过于频繁。
在top监控页面,按shift+h切换到线程监控状态
jstack java进程 |grep -A 30 3005
15、JDK 中有哪几个线程池?顺带把线程池讲了个遍
16、SQL 优化的常见方法有哪些
17、SQL 索引的顺序,字段的顺序
为什么要创建组合索引呢?这么简单的情况直接创建一个order_id的索引不就行了吗?
如果只有一个order_id索引,没什么问题,会用到这个索引,然后mysql要去磁盘上的表里面取到product_id。
如果有组合索引的话,mysql可以完全从索引中取到product_id,速度自然会快。
再多说几句组合索引的最左优先原则:
组合索引的第一个字段必须出现在查询组句中,这个索引才会被用到。
多列索引,由于索引文件以B-Tree格式保存,所以我们不用扫描任何记录,即可得到最终结果。
最左前缀:顾名思义,就是最左优先,上例中我们创建了lname_fname_age多列索引,相当于创建了(lname)单列索引,(lname,fname)组合索引以及(lname,fname,age)组合索引。
18、查看 SQL 是不是使用了索引?(有什么工具)
19、TCP 和 UDP 的区别?TCP 数据传输过程中怎么做到可靠的?
UDP 与 TCP 的主要区别在于 UDP 不一定提供可靠的数据传输。
TCP的目的是提供可靠的数据传输,并在相互进行通信的设备或服务之间保持一个虚拟连接。TCP在数据包接收无序、丢失或在交付期间被破坏时,负责数据恢复。它通过为其发送的每个数据包提供一个序号来完成此恢复。
20、说下你知道的排序算法吧
21、查找一个数组的中位数?
基本思路是:任意挑一个元素,以该元素为支点,将数组分成两部分,左部分是小于等于支点的,右部分是大于支点的。如果你的运气爆棚,左部分正好是(n-1)/2个元素,那么支点的那个数就是中位数。如果左侧长度<(n-1)/2, 那么中位点在右侧,反之,中位数在左侧。 进入相应的一侧继续寻找中位点。
这种方法很快,但是在最坏的情况下时间复杂度为O(N^2), 不过平均时间复杂度好像是O(N)。
22、你有什么问题想问我的吗?
二面
1、自我介绍、工作经历、技术栈
2、项目中你学到了什么技术?(把三项目具体描述了很久)
3、微服务划分的粒度
4、微服务的高可用怎么保证的?
5、常用的负载均衡,该怎么用,你能说下吗?
6、网关能够为后端服务带来哪些好处?
7、Spring Bean 的生命周期
8、xml 中配置的 init、destroy 方法怎么可以做到调用具体的方法?
9、反射的机制
10、Object 类中的方法
11、hashcode 和 equals 方法常用地方
12、对象比较是否相同
13、hashmap put 方法存放的时候怎么判断是否是重复的
14、Object toString 方法常用的地方,为什么要重写该方法
15、Set 和 List 区别?
16、ArrayList 和 LinkedList 区别
17、如果存取相同的数据,ArrayList 和 LinkedList 谁占用空间更大?
18、Set 存的顺序是有序的吗?
19、常见 Set 的实现有哪些?
20、TreeSet 对存入对数据有什么要求呢?
21、HashSet 的底层实现呢
22、TreeSet 底层源码有看过吗?
23、HashSet 是不是线程安全的?为什么不是线程安全的?
24、Java 中有哪些线程安全的 Map?
25、Concurrenthashmap 是怎么做到线程安全的?
26、HashTable 你了解过吗?
27、如何保证线程安全问题?
28、synchronized、lock
29、volatile 的原子性问题?为什么 i++ 这种不支持原子性?从计算机原理的设计来讲下不能保证原子性的原因
30、happens before 原理
31、cas 操作
32、lock 和 synchronized 的区别?
33、公平锁和非公平锁
34、Java 读写锁
35、读写锁设计主要解决什么问题?
36、你项目除了写 Java 代码,还有前端代码,那你知道前端有哪些框架吗?
37、MySQL 分页查询语句
38、MySQL 事务特性和隔离级别
39、不可重复读会出现在什么场景?
40、sql having 的使用场景
41、前端浏览器地址的一个 http 请求到后端整个流程是怎么样?能够说下吗?
42、http 默认端口,https 默认端口
43、DNS 你知道是干嘛的吗?
44、你们开发用的 ide 是啥?你能说下 idea 的常用几个快捷键吧?
45、代码版本管理你们用的是啥?
46、git rebase 和 merge 有什么区别?
47、你们公司加班多吗?
48、后面一起聊 high 了,之间扯了些蛋,哈哈哈
说下jvm的垃圾回收机制
说下hashmap和hashset的实现机制,源码
说下1.8前后currenthashmap的变化,为什么
如何保证数据完整性
数据库的隔离级别
Java中线程池说下
设计秒杀商品情况?redis、队列
数据库的分表分库
mysql稳定性方式
sync和reen 的却别和性能情况介绍
Java里面内置锁(synchronized)和Lock(ReentrantLock)都是可重入的。
synchronized和ReentrantLock的比较
1.区别:
1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
5)Lock可以提高多个线程进行读操作的效率。
2.两者在锁的相关概念上区别:
1)可中断锁
顾名思义,就是可以相应中断的锁。
在Java中,synchronized就不是可中断锁,而Lock是可中断锁。如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,这种就是可中断锁。
lockInterruptibly()的用法体现了Lock的可中断性。
2)公平锁
公平锁即尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该锁(并不是绝对的,大体上是这种顺序),这种就是公平锁。
非公平锁即无法保证锁的获取是按照请求锁的顺序进行的。这样就可能导致某个或者一些线程永远获取不到锁。
在Java中,synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序。ReentrantLock可以设置成公平锁。
3)读写锁
读写锁将对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁。
正因为有了读写锁,才使得多个线程之间的读操作可以并发进行,不需要同步,而写操作需要同步进行,提高了效率。
ReadWriteLock就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。
可以通过readLock()获取读锁,通过writeLock()获取写锁。
4)绑定多个条件
一个ReentrantLock对象可以同时绑定多个Condition对象,而在synchronized中,锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含的条件,如果要和多余一个条件关联的时候,就不得不额外地添加一个锁,而ReentrantLock则无须这么做,只需要多次调用new Condition()方法即可。
3.性能比较
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时ReentrantLock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
在JDK1.5中,synchronized是性能低效的。因为这是一个重量级操作,它对性能最大的影响是阻塞的是实现,挂起线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性带来了很大的压力。相比之下使用Java提供的ReentrankLock对象,性能更高一些。到了JDK1.6,发生了变化,对synchronize加入了很多优化措施,有自适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在JDK1.6上synchronize的性能并不比Lock差。官方也表示,他们也更支持synchronize,在未来的版本中还有优化余地,所以还是提倡在synchronized能实现需求的情况下,优先考虑使用synchronized来进行同步。
- 目前系统怎么更加优化
12.