一、Java基础
1、说说spring中的IOC和AOP
IOC:IOC容器帮我们创建对象,不需要程序员去手动创建。IOC就像一个工厂一样,当我们需要一个对象的时候,只需要写java代码或者xml文件,IOC就会在适当的时候创建,通过DI自动注入,我们不需要关心这些bean是如何创建的。DI就像打疫苗一样,我们不需要知道疫苗是如何被制造出来的,只需要到指定点去告诉医务人员要打疫苗,相当于编写java代码或者xml文件,医务人员就会将疫苗注入我们体内。IOC还有一个重要的作用是解耦合。比如我们需要jdbctemplate,使用Druid的数据源,假如jdbctemplate和Druid强耦合在一起,那么我们就无法更换数据源。而IOC会自动地帮我们注入jdbctemplate,让他依赖一个DataSource接口,而不是具体的数据源,这样无论我们使用什么数据源都可以工作。并且IOC管理着许多单例的bean,在我们要使用的时候直接调用即可。
然后说说AOP。面向切面编程。他可以将一些固定套路的代码抽取出来,例如事务处理的开启连接提交回滚关闭连接,在需要使用的时候切入到程序中,这样大大地方便了程序员,也降低了耦合度。
2、HashMap的底层是如何实现的?
hashmap底层原理分版本。jdk1.7中通过数组+链表实现;jdk1.8中通过数组+链表+红黑树实现。之所以要引入红黑树,是因为链表的查询效率太低。当hashmap中计算出的多个index值发生冲突,需要存放到链表中时,查询数据需要从头查到尾,时间复杂度为n,而在jkd1.8中,当数组长度大于等于64且链表长度大于8时,会将冲突的index放入红黑树中,红黑树查询的时间复杂度为logn。
3、HashMap根据key查询的时间复杂度?
hashmap根据key查询的时间复杂度:如果没有index冲突,时间复杂度为1;如果有冲突,存放在链表中为n;存放在红黑树中为logn
4、你知道几种排序算法?说说它们的时间复杂度?
5、synchronized底层原理
synchronized可以同步代码。所谓同步代码,就是让同一时刻只能有一个线程来执行代码。synchronized可以标记对象和方法,其实就是修改锁对象头中Mark word的锁标识位和偏向锁标识位
6、HashMap是线程安全的吗?ConcurrentHashMap的实现原理?
7、Java中线程同步的方式有哪些?
8、说说hashmap的扩容机制?
hashmap在存储数据过多时就会进行扩容,以免影响运行效率。当数据超过容量与负载因子的乘积时,就会进行扩容。hashmap扩容时会创建一个原数组两倍大的数组,然后遍历原数组,将原来所有的数据都移到新数组中。扩容之后需要重新hash,因为hash值是hashcode &(length-1)计算的,扩容后长度改变,hash值也会随之改变。在jdk1.7中,扩容采用的是头插法,头插法会改变原节点的位置,在多线程的情况下,原先按顺序排列的链表就会出现收尾相连的问题,所以在jdk1.8之后就采用了尾插法。其实扩容操作对于效率的影响是很大的,所以我们在使用hashmap时应该计算好需要的大小,尽量避免出现扩容操作而影响效率 。
9、说说instanceof吧?
Java instanceof用法详解_测试极客-CSDN博客_instanceof用法
10、HashMap 与HashTable的区别
HashMap 与HashTable的区别_wangxing233的博客-CSDN博客
11、说说OOP吧?
12、并发编程的简单了解
13、Java锁机制了解吗?知道的都说一下!
浅谈Java锁机制_WuSheng的博客-CSDN博客_java锁机制
14、Java多线程,看这一篇就够了
15、那你能详细说一下synchronized 和Lock区别吗?
synchronized 和Lock区别_洞玄之境的博客-CSDN博客_synchronized和lock的区别
16、说说你对AQS的理解
AQS 是多线程同步器,它是 J.U.C 包中多个组件的底层实现,如 Lock、 CountDownLatch、Semaphore 等都用到了 AQS. 从本质上来说,AQS 提供了两种锁机制,分别是排它锁,和共享锁。 排它锁,就是存在多线程竞争同一共享资源时,同一时刻只允许一个线程访问该 共享资源,也就是多个线程中只能有一个线程获得锁资源,比如 Lock 中的 ReentrantLock 重入锁实现就是用到了 AQS 中的排它锁功能。 共享锁也称为读锁,就是在同一时刻允许多个线程同时获得锁资源,比如 CountDownLatch 和 Semaphore 都是用到了 AQS 中的共享锁功能。
设计AQS整个体系需要解决的三个核心的问题:①互斥变量的设计以及多线程同时更新互斥变量时的安全性②未竞争到锁资源的线程的等待以及竞争到锁资源的线程释放锁之后的唤醒③锁竞争的公平性和非公平性。
AQS采用了一个int类型的volatile变量state用来记录锁竞争的一个状态,0表示当前没有任何线程竞争锁资源,而大于等于1表示已经有线程正在持有锁资源。一个线程来获取锁资源的时候,首先判断state是否等于0,如果是(无锁状态),则把这个state更新成1,表示占用到锁。此时如果多个线程进行同样的操作,会造成线程安全问题。AQS采用了CAS机制来保证互斥变量state的原子性。未获取到锁资源的线程通过Unsafe类中的park方法对线程进行阻塞,把阻塞的线程按照先进先出的原则加入到一个双向链表的结构中,当获得锁资源的线程释放锁之后,会从双向链表的头部去唤醒下一个等待的线程再去竞争锁。另外关于公平性和非公平性问题,AQS的处理方式是,在竞争锁资源的时候,公平锁需要判断双向链表中是否有阻塞的线程,如果有,则需要去排队等待;而非公平锁的处理方式是,不管双向链表中是否存在等待锁的线程,都会直接尝试更改互斥变量state去竞争锁。
二、数据库
1、如何进行MySQL的性能优化
MySQL的性能优化可以分为四个部分:一是硬件和操作系统层面的优化。从硬件方面来说,影响MySQL性能的主要因素是CPU、可用内存大小、磁盘读写速度、网络带宽;从操作系统层面来讲,主要是操作系统的网络配置,这部分的优化主要是由DBA或者是运维工程师完成,主要还是避免资源浪费;二是架构设计层面的优化。mysql是一个磁盘IO访问非常频繁的关系型数据库,在高并发和高性能的场景中,MySQL必然要承受巨大的并发压力。在此时我们优化的方式主要可以分为:
1、搭建MySQL主从集群,因为单个MySQL服务器容易导致单点故障,一旦服务宕机,将会导致依赖MySQL服务的应用全部无法响应,主从集群或者主主集群都可以去保证服务的高可用性;
2、读写分离设计,在读多写少的场景中,可以避免读写冲突导致的性能问题;
3、引入分库分表的机制。通过分库可以减少单个服务器承受的IO压力;通过分表可以降低单表数据量,从而提高SQL查询的效率;
4、针对热点数据可以引入更为高效的分布式数据库,比如Redis,他可以很好的缓解MySQL的访问压力;三是MySQL程序配置优化。一般可以通过MySQL配置文件my.cmf来完成;四是SQL优化,可以分为几个步骤:
1、慢SQL的定位和排查。可以通过慢查询日志和慢查询日志工具分析得到有问题的SQL列表;
2、执行计划分析,针对慢SQL,可以使用关键字explain来查看当前SQL的执行计划。其中,语句的优化包括:
(1)选择合适的字段类型(更小的,更简单的,并且要指定not null)
(2)使用join代替子查询
(3)使用union代替or,避免创建临时表
(4)尽量不是用like,即使使用也不要用‘%’
(5)知道查询数量的话,直接使用limit
(6)不用count(id),要用count(*)
(7)在建有索引的字段上不要使用函数
(8)锁定表,保证数据的完整性
(9)使用事务,保证数据的完整性和一致性
2、Redis的持久化机制?
3、什么是缓存雪崩、缓存击穿和缓存穿透?有什么区别?
4、Redis如何实现分布式锁?
5、说说MySQL中的聚簇索引和非聚簇索引?
6、如何保证Redis和MySQL的数据一致性?
(1)低并发情况下:
读操作:先读Redis,不存在就去读MySQL,再把数据回写到Redis中
写操作:先写MySQL,成功后再写入Redis
(2)高并发情况下:
读操作:同低并发情况
写操作:异步写入。先写入Redis,然后定期更新到MySQL中
7 、说一下hash索引,为什么innodb索引结构要用树型而不用hash?
(1) hash索引仅能满足(=)、(<>)和 IN 查询。如果进行范围查询,哈希值的索引时间复杂度为退化为O(n);而树的能够保证log2N的高效率;
(2)hash索引数据存储是没有顺序的,在 ORDER BY情况下,使用hash索引还需要对数据进行重新排序;
(3)对于联合索引的情况,hash值是将联合索引键合并后一起来计算的,无法对单独的一个键或者几个索引键进行查询;
(4)对于等值查询来说,通常hash索引的效率更高,不过也存在一种情况,就是索引列的重复值如果很多,效率就会降低。这是因为遇到hash冲突时,需要遍历同中的行指针来进行比较,找到查询的关键字,非常耗时。所以,hash索引通常不会用到重复值多的列上,比如列为性别、年龄的情况等。
8、谈谈你对MVCC的理解
我对MVCC的理解可以从数据库的三种并发场景来说:第一种是读和读的并发,也就是多个线程同时进行读操作,这种情况下不会产生任何并发问题;第二种是读写并发,也就是两个线程在同一时刻分别对数据库进行读写操作,这个时候可能会造成三个问题:1、事务隔离性问题;
2、会出现脏读、幻读、不可重复读的问题;第三种是写写并发,就是两个线程同时进行写操作,这种情况下可能出现丢失修改的问题。MVCC就是为了事务操作中并发安全问题的无锁并发控制技术,全称为Muti-Version Concurrency Control,也就是多版本并发控制,他是通过数据库中的隐式字段undo log和Read View来实现的,具体实现原理:简单聊聊MVCC_玉面大蛟龙的博客-CSDN博客
三、网络原理
1、负载均衡的实现方法有哪些?
(1)dns
用户的请求发送到dns服务器上,会返回一个ip地址,用户根据这个ip地址去访问服务器
(2)硬件服务器
通过一些大型的交换机实现负载均衡。好处是有专门的人来维护,缺点是太贵
(3)软件服务器 例如Nginx
大多数企业使用。好处是免费开源,企业可以根据自己的需求做二次封装
2、负载均衡的算法有哪些?
3、OSI七层模型是什么,它们分别有哪些作用?
从上到下记忆口诀:应、表、会、传、网、数、物
1)应用层:用户APP里的数据(图片、视频、文字等)
(2)表示层:对APP数据进行编码(将这些东西编译成为计算机语言,如果使用自定义的编码,就还具有加密的作用)
(3)会话层:两个APP之间的会话(例如美团只能微信支付、淘宝只能支付宝支付)
(4)传输层:简历TCP或UDP连接
(5)网络层:基于IP地址进行路由转发
(6)数据链路层:各段链路的通信协议
(7)物理层:通过物理介质进行传输(网线、光纤等)
4、ARP协议的作用?
5、使用ARP协议的几种典型情况?
6、TCP的流量控制和拥塞控制的区别?
流量控制为了解决发送速率和接收速率不匹配的问题而控制发送方的发送速率,拥塞控制是因为网络堵塞,控制发送方的发送速率,避免更堵塞。
7、TCP流量控制采用什么方法?
8、TCP拥塞控制采用什么方法?
拥塞控制有四种算法:慢开始、拥塞避免、快重传、快恢复
(1)慢开始
不要一开始就发送大量的数据,由小到大逐渐增加拥塞窗口的大小。那如果说当前窗口发送的报文全都收到了确认报文,这个时候我就将窗口的大小乘二,也就是说它是乘二的指数增长的,比如刚开始窗口的大小是1,之后就是2、4、8。那这个从一开始的指数级增长的一个窗口大小变化就称为慢开始。
(2)拥塞避免
那为了避免cwnd的值增长过快呢就需要进行一个限制,这个时候就引入慢开始的一个阈值,那一旦当前窗口大小大于这个ssthresh阈值呢,就要采用拥塞避免算法,拥塞避免算法也是让cwnd增大的,只不过增长的没那么快了,它是呈线性增长的。那一直增大cwnd的大小,它肯定会到达一个网络拥塞的状态,这个时候呢就会发生超时,一旦发生超时,这个时候发送方就可以认为发生了网络阻塞,他就会把阈值变成当前窗口大小的一半,接着呢依然去采用慢开始算法,从1开始增长,达到阈值继续采用拥塞避免算法。
(3)快重传
但是有时候报文丢了,不代表网络阻塞了,所以说TCP引入了第三种算法,称之为快重传。就是让发送方直到个别的报文段丢失了,快重传要求接收方收到有序报文数据后,那你就立刻发送确认报文。比如发送方发送的是m1,m2,m3,m4,m5。那么接收方接收到了m1,m2,m4,m5,接收方会确认m1,m2,不会去确认m4,m5,并且会重复确认m2,在重复确认m2三次后,就会触发快重传。发送端知道接收端没有收到m3,会赶紧给接收端发送 m3,而平常的话,会有一个超时时间,通过快重传就不用去等待那么长的超时时间了。那这样就可以避免超时。
(4)快恢复
快重传之后依然要降低阈值,但是它不需要从1开始,而是从阈值开始,也就是省去了一个慢开始的阶段。那快速到达阈值的算法就称为快恢复。
9、TCP的首部结构?
TCP首部最小长度为20字节 。
10、cookie、session、token分别有什么作用?有什么区别?
cookie的过程:
浏览器发送HTTP请求,服务器会进行cookie设置。cookie里有名和值两个重要属性,服务器会把名和值属性里的内容给填充完整。cookie发给浏览器后,浏览器会保存起来。但是cookie并不安全,所以就有了session的概念。
session的过程:
我们将用户名密码发送到服务器,服务器校验正确,创建一个Session ID和会话结束时间,然后将Session ID和会话结束时间发送至浏览器。浏览器设置cookie,并把session ID加入到cookie中,再把会话结束时间设置为这个cookie的有效期。session ID是一个包含用户信息但没有规律的字符串,即使黑客在浏览器中拿到了session ID,也无法根据其推断出用户信息。浏览器每次访问服务器时,都会将这个session ID发送到服务器,直至达到会话结束时间,这时浏览器一般会自行删除cookie。在此之后如果用户还想登录,那就要重新输入用户名密码了。但是随着用户的增多,服务器保存的session ID也会增多,如果服务器使用集群,在一个服务器中的session又需要共享到其他服务器中,这就需要用到token。
cookie和session最大的区别是数据存储的位置不同,cookie是将数据存储在浏览器中的,session是将数据存储在服务器中的。所以就单论数据安全性来说,cookie是非常低的,而session是相对较高的。
token介绍:可以看我的博客 浅析单点登录(重点讲解OAuth2+JWT)
11、HTTP和HTTPS有什么区别?
http是超文本传输协议,以明文的形式发送内容。当我们想要访问一个网站时,进行登录操作,http就会将我们的账号密码加密后发送到服务器,如果中途有人截取这些信息,我们的账号密码就有可能泄漏。
而使用HTTPS时,当浏览器想要访问服务器时,服务器会先发送一份网站的证书信息到浏览器上,这个证书信息是由权威机构颁发的。确认网站没有问题后,HTTPS使用非对称加密的方式将用户信息加密。所谓非对称加密,就是使用公钥加密、私钥解密,而因为黑客无法获得服务器的私钥,那么即使他截取了信息,也无法破译,这样就保证了数据传输的安全。
12、浏览器输入www.baidu.com,背后发生了什么?
13、RPC协议和HTTP协议的区别?
从三个方面回答:
1、从功能层面来说,HTTP是一个应用层的超文本传输协议,他是万维网数据传输通信的基础,也就是说主要服务与网页端和服务端的数据传输上;而RPC是一个远程过程调用协议,他是定位在实现不同计算机应用之间的数据通信,屏蔽了通信的底层复杂度,让开发者像调用本地服务一样来完成远程服务的调用,rpc≈序列化+传输层协议+ 特定协议(服务注册,负载均衡等);
2、从实现层面上来说,HTTP是一个已经实现并且成熟的应用层协议,他定义了通信报文的一些格式,比如request body、request header、response body、response header等,符合这些格式的协议才是HTTP协议;RPC协议是一种通信协议的规范,他并没有具体实现,只有按照RPC协议去实现的通信框架才是RPC框架,比如Dubbo、gRPC、HSF等,因此我们可以在实现RPC框架的时候,自定义报文通信的协议规范、自定义序列化方式、或者自定义网络通信协议的类型等等。所以从这个层面来说,HTTP是一个成熟的应用层协议,而RPC只是定义了不同服务之间数据通信的规范;
3、从应用层面来说,HTTP协议和实现了RPC协议的框架都能够去实现跨网络节点的服务通信,并且他们底层都实现了TCP协议作为通信基础。但是由于RPC只是一种标准协议,符合该协议的框架都是RPC框架,因此RPC网络通信协议层也可以使用HTTP来实现,比如OpenFeign底层就采用了HTTP协议作为通信基础。
四、操作系统
1、死锁产生的条件?
互斥使用、占有并等待、不可剥夺、循环等待
2、如何解决死锁
解决死锁,就需要破坏死锁的必要条件
(1)破坏互斥使用:一般资源只能一个人使用,不破坏
(2)破坏占有并等待:一个线程如果申请不到资源,就要放弃他手里已经抢占到的所有资源
(3)破坏不可剥夺:一个线程必须一次性申请到他所需要的所有资源,否则等待
(4)破坏循环等待:资源按照大小,按顺序申请
(5)使用银行家算法
3、进程和线程的区别
4、进程间的通信方式?
同一个进程中的线程共享数据空间可以直接通信,但是进程间是无法直接进行通信的。
进程间通信方式:
(1)管道模型:比如cat xx.txt | grep -n 'xxx' 这个'|'可以看作一个单向的匿名管道,使得前后两个进程之间进行通信,前一个命名的输出作为后一个命令的输入,该管道使用结束则立即销毁。命名管道在linux中以文件的形式存在,只要访问该文件就可以实现任意两个进程间的通信,命名管道可以看作是是硬盘上存在的设备文件,所以打开需要使用open。
(2)消息队列模型:比如生产者消费者模式,一端生产一端消费数据。遵循严格的先进先出。
(3)共享内存:多用于传输一些大文件,如果采用管道或者消息队列传输大文件,涉及到重复拷贝,比较消耗性能,因此模拟多线程,在内存中开辟一块特殊的内存用于多个进程共享访问。也是进程间最高效的通信方式。
(4)信号量机制:信号量可以看作一种数据操作锁,通过对临界资源的控制访问以管理进程之间的通信,PV原语操作。
(5)socket:用于多个进程之间的网络传输。可以是单机多进程也可以是不同机器上的多进程通信。打开的socket在linux下也是以文件描述符fd存在。服务端创建套接字,绑定ip端口,监听端口号,等待客户端调用,客户端创建之后与服务端TCP三次握手建立连接完成,双方就可以发送和接收数据。