2021年,54道大厂面试题:附完整答案!(1)

1、HashMap的时间复杂度分析

put操作的流程:

第一步:key.hashcode(),时间复杂度O(1)。

第二步:找到桶以后,判断桶里是否有元素,如果没有,直接new一个entey节点插入到数组中。时间复杂度O(1)。

第三步:如果桶里有元素,并且元素个数小于6,则调用equals方法,比较是否存在相同名字的key,不存在则new一个entry插入都链表尾部。时间复杂度O(1)+O(n)=O(n)。

第四步:如果桶里有元素,并且元素个数大于6,则调用equals方法,比较是否存在相同名字的key,不存在则new一个entry插入都链表尾部。时间复杂度O(1)+O(logn)=O(logn)。红黑树查询的时间复杂度是logn。

通过上面的分析,我们可以得出结论,HashMap新增元素的时间复杂度是不固定的,可能的值有O(1)、O(logn)、O(n)。

2、关于Java中HashTable和HashMap的区别:

1、继承: HashTable继承自Dirctionary,HashMap继承自AbstractMap,二者均实现了Map接口; 2、线程安全性: HashTable的方法是同步的,即是线程安全的。HaspMap的方法不是同步的,不是线程安全的的。在多线程并发的情况下,我们可以直接使用HashTable,如果 要使用HashMap,就需要自行对HashMap的同步处理。 3、键值: HashTable中不允许有null键和null值,HashMap中允许出现一个null键,可以存在一个或者多个键的值都为null。程序中,对于HashMap,如果使用get(参数为 键)方法时,返回结果为null,可能是该键不存在,也可能是该键对应的值为null,这就出现了结果的二义性。因此,在HashMap中,我们不能使用get()方法来查询键 对应的值,应该使用containskey()方法。 4、遍历: 这两个在遍历方式的实现不同。HashTable和HashMap两者都实现了Iterator。但是,由于历史原因,HashTable还使用了Enumeration。 5、哈希值: HashTable是直接使用对象的hashCode。HashMap是重新计算hash值。 6、扩容: HashTable和HashMap的底层实现的数组和初始大小和扩容方式。HashTable初始大小为11,并且每次扩容都为:2old+1。HashMap的默认大小为16,并且一 定是2的指数,每次扩容都为old2。

3、为什么用B+树存储索引而不是Hash索引?Hash索引它O(1)不是更快吗?

查询单条数据确实Hash索引快,但同上,B+树支持 范围查询 ,而Hash索引做不到。

而且数据库索引一般存储在磁盘中,加载进内存中如果数据量大的话 无法一次装入内存 ,B+树的设计可以允许数据 分批加载 ,同时树的高度较低,提高查找效率。

4、BST(二叉搜索树)

BST(Binary Search Tree)目的是为了提高查找的性能,其查找在平均和最坏的情况下都是logn级别,接近二分查找。

其特点是:每个节点的值大于其任意左侧子节点的值,小于其任意右节点的值

5、Mysql回表

回表就是先通过数据库索引扫描出数据所在的行,再通过行主键id取出索引中未提供的数据,即基于非主键索引的查询需要多扫描一棵索引树。

什么时候需要回表?什么时候不需要回表? 答:聚簇索引和覆盖索引不需要回表,其他情况都需要回表

6、联合索引

当我们的where查询存在多个条件查询的时候,我们需要对查询的列创建组合索引

最左匹配原则

只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用复合索引时遵循最左前缀集合,所以在建立联合索引的时候查询最频繁的条件要放在左边

7、linux常用命令

shutdown ===关机 reboot ==重启 目录切换===cd 目录查看===ls

创建目录===mkdir 删除目录===rm help==帮助 man==说明书

目录修改===mv 搜索目录===find 查看当前工作目录==pwd

新增文件==touch 删除文件===rm 复制文件==cp 修改文件===vim 文件查看===cat/more/less/tail/head

修改权限===chmod

压缩文件===tar 查找命令===grep/find/locate/whereis/which

切换用户===su/sudo

==================================0==================================

显示磁盘==df -l 文件或目录磁盘的使用===du

创建连接===ln -s(软连接,无S硬) 时间==date

查看当前运行的进程状态,一次性===ps

显示当前系统正在执行的进程的相关信息,包括进程ID、内存占用率、CPU占用率等==top

kill 显示系统内存使用情况====free

==================================0======================================

显示文件详细信息==stat who===在线登录用户 whoami===操作用户

主机名==hostname 系统信息===uname 查看网络情况====ifconfig

测试网络连通===ping 显示网络状态信息===netstart

8、java基础之ArrayList和Vector的主要区别

List接口下一共实现了三个类:ArrayList,Vector,LinkedList。 LinkedList主要保持数据的插入顺序的时候使用,采用链表结构。

ArrayList,Vector主要区别为以下几点: (1):Vector是线程安全的,源码中有很多的synchronized可以看出,而ArrayList不是。导致Vector效率无法和ArrayList相比; (2):ArrayList和Vector都采用线性连续存储空间,当存储空间不足的时候,ArrayList默认增加为原来的50%,Vector默认增加为原来的一倍; (3):Vector可以设置capacityIncrement,而ArrayList不可以,从字面理解就是capacity容量,Increment增加,容量增长的参数。

9、排序

10、拥塞控制

TCP的四种拥塞控制算法 1.慢开始

一开始注入的报文段少,cwnd慢慢增加 1-2-4-8,收到多少个确认报文,就增加多少个cwnd,若当前的拥塞窗口cwnd的值已经等于慢开始门限值,之后改用拥塞避免算法

2.拥塞避免

就是每个传输轮次,拥塞窗口cwnd只能线性加一

只要网络出现拥塞(没有按时到达)时,就把ssthresh的值置为出现拥塞时的拥塞窗口的一半(但不能小于2),以及cwnd置为1,进行慢开始。

3.快重传

连续收到3个重复的确认报文端,就认为是拥塞发生了

收到三个确认,发送方尽快进行重传,不需要等待超时重传定时器溢出

4.快恢复

降低满开始和拥塞窗口的值为一半,将CWND设置为新的ssthresh(减半后的ssthresh),然后开始执行拥塞避免算法

11、深浅克隆

深克隆实现方法:重写clone方法,clone中嵌套clone

12、一个long整型,判断其二进制有多少个0

先进行与运算,等于1则one++,否则0++,然后右移一位

13、Mysql架构

MySQL逻辑架构整体分为三层 : 1> 客户端 : 并非MySQL所独有,诸如 : 连接处理、授权认证、安全等功能均在这一层处理 2> 核心服务 : 包括查询解析、分析、优化、缓存、内置函数(比如 : 时间、数学、加密等函数),所有的跨存储引擎的功能也在这一层实现 : 存储过程、触发器、视图等 3> 存储引擎 : 负责 MySQL 中的数据存储和提取,和 Linux 下的文件系统类似,每种存储引擎都有其优势和劣势,中间的服务层通过 API 与存储引擎通信,这些 API接口 屏蔽不同存储引擎间的差异

14、协程

协程:就是在单线程的情况下,让多个任务实现并发的效果(切换+保存状态)

线程进程都是同步机制,而协程则是异步

15、Mysql是什么类型的数据库

开放源代码的关系型数据库管理系统

16、InnoDB

InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级锁。

共享/排它锁(Shared and Exclusive Locks)

按照兼容性来分类,InnoDB有共享锁和排它锁两种行级锁。

  • 共享锁(S):又称读锁。允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

  • 排他锁(X):又称写锁。允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。

17、事务

1、事务是什么

   事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。

2、事务的四大特性

数据库事务 transanction 正确执行的四个基本要素。ACID,原子性(Atomicity)、一致性(Correspondence)、隔离性(Isolation)、持久性(Durability)。

18、无锁机制

CAS====

ThreadLocal

从名字我们就可以看到ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的

使用场景

1、在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。

2、线程间数据隔离

3、进行事务操作,用于存储线程事务信息。

4、数据库连接,Session会话管理。

ThreadLocal的作用是每一个线程创建一个副本

避免内存溢出:ThreadLocal是null了,也就是要被垃圾回收器回收了,但是此时我们的ThreadLocalMap生命周期和Thread的一样,它不会回收,这时候就出现了一个现象。那就是ThreadLocalMap的key没了,但是value还在,这就造成了内存泄漏。

解决办法:使用完ThreadLocal后,执行remove操作,避免出现内存溢出情况

19、Springboot自动装配

总结:

@EnableAutoConfiguration作用就是从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

这些功能配置类要生效的话,会去classpath中找是否有该类的依赖类(也就是pom.xml必须有对应功能的jar包才行)并且配置类里面注入了默认属性值类,功能类可以引用并赋默认值。生成功能类的原则是自定义优先,没有自定义时才会使用自动装配类。

20、HashMap1.7/1.8区别

  1. 最重要的一点是底层结构不一样,1.7是数组+链表,1.8则是数组+链表+红黑树结构;

  2. jdk1.7中当哈希表为空时,会先调用inflateTable()初始化一个数组;而1.8则是直接调用resize()扩容;

  3. 插入键值对的put方法的区别,1.8中会将节点插入到链表尾部,而1.7中是采用头插;(红黑树)

  4. jdk1.7中的hash函数对哈希值的计算直接使用key的hashCode值,而1.8中则是采用key的hashCode异或上key的hashCode进行无符号右移16位的结果,避免了只靠低位数据来计算哈希时导致的冲突,计算结果由高低位结合决定,使元素分布更均匀;

  5. 扩容时1.8会保持原链表的顺序,而1.7会颠倒链表的顺序;而且1.8是在元素插入后检测是否需要扩容,1.7则是在元素插入前;

  6. jdk1.8是扩容时通过hash&cap==0将链表分散,无需改变hash值,而1.7是通过更新hashSeed来修改hash值达到分散的目的;

  7. 扩容策略:1.7中是只要不小于阈值就直接扩容2倍;而1.8的扩容策略会更优化,当数组容量未达到64时,以2倍进行扩容,超过64之后若桶中元素个数不小于7就将链表转换为红黑树,但如果红黑树中的元素个数小于6就会还原为链表,当红黑树中元素不小于32的时候才会再次扩容。

  8. 在扩容的时候:1.7在插入数据之前扩容,而1.8插入数据成功之后扩容。

21、ConcurrentHashMap1.7/1.8区别

1、最重要的一点是底层结构不一样,1.7是数组+链表,1.8则是数组+链表+红黑树结构;

2、其中抛弃了原有的 Segment 分段锁,而采用了 CAS + synchronized 来保证并发安全性。

1因为粒度降低了,在相对而言的低粒度加锁方式,synchronized并不比ReentrantLock差,在粗粒度加锁中ReentrantLock可能通过Condition来控制各个低粒度的边界,更加的灵活,而在低粒度中,Condition的优势就没有了 2JVM的开发团队从来都没有放弃synchronized,而且基于JVM的synchronized优化空间更大,使用内嵌的关键字比使用API更加自然 3在大量的数据操作下,对于JVM的内存压力,基于API的ReentrantLock会开销更多的内存,虽然不是瓶颈,但是也是一个选择依据

22、ConcurrentHashMap和 hashTable的保证线程安全的机制有何联系

Hashtable通过synchronized修饰方法 来保证线程安全 通过synchronized同步代码块和 CAS操作来实现线程安全 由此抛出的问题: 为什么要用synchronized,cas不是已经可以保证操作的线程安全吗? 原因: CAS也是适用一些场合的,比如资源竞争小时,是非常适用的,不用进行内核态和用户态之间的线程上下文切换,同时自旋概率也会大大减少,提升性能,但资源竞争激烈时(比如大量线程对同一资源进行写和读操作)并不适用,自旋概率会大大增加,从而浪费CPU资源,降低性 能

23、聚集索引

聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个

聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续

聚集索引:物理存储按照索引排序;聚集索引是一种索引组织形式,索引的键值逻辑顺序决定了表数据行的物理存储顺序

非聚集索引:物理存储不按照索引排序;非聚集索引则就是普通索引了,仅仅只是对数据列创建相应的索引,不影响整个表的物理存储顺序.

索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。

24、Hash算法解决冲突的方法

1, 开放定址法:

2, 再哈希法

3, 链地址法

4, 建立公共溢出区

25、GC ROOTS

方法运行时,方法中引用的对象;类的静态变量引用的对象;类中常量引用的对象;Native方法中引用的对象(本地方法栈中JNI(即一般说的Native方法)引用的对象;)

26、OSI模型中各层传输的基本单位

协议数据单元(PDU) 每一次层得协议数据单元如下:

比特流(bit):物理层/一层。

数据帧(frame):数据链路层/二层。

数据包/报文分组(packet):网络层/三层。

数据报(datagram):传输层 UDP/四层。

数据段(segment):传输层 TCP/四层。

消息/报文(message):三层以上,通常指应用层/七层。

27、计算机各层网络协议

1、物理层:(典型设备:中继器,集线器、网线、HUB) 数据单元:比特 (Bit)

以太网物理层、调制解调器、PLC 、SONET/SDH 、G.709 、光导纤维、 同轴电缆、双绞线

2、数据链路层: (典型设备: 网卡,网桥,交换机) 数据单元:帧 (Frame)

ARQ(Automatic Repeat-reQuest )自动重传请求协议

停止等待协议: CSMA/CD

PPP(Point-to-Ponit Protocol)点对点协议面向字节

3、网络层: (典型设备:路由器,防火墙、多层交换机) 数据单元:数据包(Packet )

IP

ARP (Address Resolution Protocol) 即地址解析协议,实现通过IP 地址得 知其物理地址。

ICMP (Internet Control Message Protocol )Internet 控制报文协议

4、传输层: (典型设备: 进程和端口) 数据单元:数据段 (Segment)

TCP、UDP

5、应用层: (典型设备:应用程序,如FTP,SMTP ,HTTP)

POP3 (Post Office Protocol 3) 即邮局协议的第3 个版本,用于接受邮件

28、DNS查找过程

\1. 浏览器先检查自身缓存中有没有被解析过的这个域名对应的ip地址,如果有,解析结束。同时域名被缓存的时间也可通过TTL属性来设置。

\2. 如果浏览器缓存中没有(专业点叫还没命中),浏览器会检查操作系统缓存中有没有对应的已解析过的结果。而操作系统也有一个域名解析的过程。在windows中可通过c盘里一个叫hosts的文件来设置,如果你在这里指定了一个域名对应的ip地址,那浏览器会首先使用这个ip地址。

\3. 如果至此还没有命中域名,才会真正的请求本地域名服务器(LDNS)来解析这个域名,这台服务器一般在你的城市的某个角落,距离你不会很远,并且这台服务器的性能都很好,一般都会缓存域名解析结果,大约80%的域名解析到这里就完成了。

\4. 如果LDNS仍然没有命中,就直接跳到Root Server 域名服务器请求解析

\5. 根域名服务器返回给LDNS一个所查询域的主域名服务器(gTLD Server,国际顶尖域名服务器,如.com .cn .org等)地址

\6. 此时LDNS再发送请求给上一步返回的gTLD

\7. 接受请求的gTLD查找并返回这个域名对应的Name Server的地址,这个Name Server就是网站注册的域名服务器

\8. Name Server根据映射关系表找到目标ip,返回给LDNS

\9. LDNS缓存这个域名和对应的ip

\10. LDNS把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束

浏览器缓存==系统缓存(本地hosts文件)==LDNS==RDNS==RDNS给LDNS gTLD==返回Name Server==返回对应ip==缓存到本地

29、HTTP协议

HTTP 特性:

  • HTTP 是无连接无状态的

  • HTTP 一般构建于 TCP/IP 协议之上,默认端口号是 80

HTTP 定义了在与服务器交互的不同方式,最常用的方法有 4 种,分别是 GET,POST,PUT, DELETE

30、HTTP2.0和HTTP1.X相比的新特性

  • 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

  • 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。

  • header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

  • 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。

    二路送头

31、快排优化

1、当待排序列长度为5~20之间,此时使用插入排序能避免一些有害的退化情形

2、尾递归优化

当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归

覆盖当前的栈帧而不是在其之上重新添加一个,这样所使用的栈空间就大大缩减了,这使得实际的运行效率会变得更高

3、随机选取枢轴

4、三数取中,假设数组被排序的范围为left和right,center=(left+right)/2,对a[left]、a[right]和a[center]进行适当排序,取中值为中轴,将最小者放a[left],最大者放在a[right]

32、hashmap扩容

默认容量16

HashMap的容量超过3/4时就需要扩容了

hash冲突是符合泊松分布的, 而冲突概率最小的是在7-8之间,取3/4在保证hash冲突小的情况下兼顾了效率

详细介绍resize方法,扩容达到上限时,将扩容阈值直接设置为Integer.MAX_VALUE以此来避免扩容。 详细介绍put方法,底层调用putVal方法,先进行插入(判断是否哈希冲突,是否红黑树结点,否就进行链表插入),又因为resize方法放在较尾部,所以综上所述先put再resize。

33、如何设计一个高并发系统?

(1)系统拆分,将一个系统拆分为多个子系统,用dubbo来搞。然后每个系统连一个数据库,这样本来就一个库,现在多个数据库,不也可以抗高并发么。

(2)缓存,必须得用缓存。大部分的高并发场景,都是读多写少,那你完全可以在数据库和缓存里都写一份,然后读的时候大量走缓存不就得了。毕竟人家redis轻轻松松单机几万的并发啊。没问题的。所以你可以考虑考虑你的项目里,那些承载主要请求的读场景,怎么用缓存来抗高并发。

(3)MQ,必须得用MQ。可能你还是会出现高并发写的场景,比如说一个业务操作里要频繁搞数据库几十次,增删改增删改,疯了。那高并发绝对搞挂你的系统,你要是用redis来承载写那肯定不行,人家是缓存,数据随时就被LRU了,数据格式还无比简单,没有事务支持。所以该用mysql还得用mysql啊。那你咋办?用MQ吧,大量的写请求灌入MQ里,排队慢慢玩儿,后边系统消费后慢慢写,控制在mysql承载范围之内。所以你得考虑考虑你的项目里,那些承载复杂写业务逻辑的场景里,如何用MQ来异步写,提升并发性。MQ单机抗几万并发也是ok的,这个之前还特意说过。

(4)分库分表,可能到了最后数据库层面还是免不了抗高并发的要求,好吧,那么就将一个数据库拆分为多个库,多个库来抗更高的并发;然后将一个表拆分为多个表,每个表的数据量保持少一点,提高sql跑的性能。

(5)读写分离,这个就是说大部分时候数据库可能也是读多写少,没必要所有请求都集中在一个库上吧,可以搞个主从架构,主库写入,从库读取,搞一个读写分离。读流量太多的时候,还可以加更多的从库。

(6)Elasticsearch,可以考虑用es。es是分布式的,可以随便扩容,分布式天然就可以支撑高并发,因为动不动就可以扩容加机器来抗更高的并发。那么一些比较简单的查询、统计类的操作,可以考虑用es来承载,还有一些全文搜索类的操作,也可以考虑用es来承载。 上面的6点,基本就是高并发系统肯定要干的一些事儿,大家可以仔细结合之前讲过的知识考虑一下,到时候你可以系统的把这块阐述一下,然后每个部分要注意哪些问题,之前都讲过了,你都可以阐述阐述,表明你对这块是有点积累的。

34、redis 使用跳表做索引,却不是用B+树做索引

因为B+树的原理是 叶子节点存储数据,非叶子节点存储索引,B+树的每个节点可以存储多个关键字,它将节点大小设置为磁盘页的大小,充分利用了磁盘预读的功能。每次读取磁盘页时就会读取一整个节点,每个叶子节点还有指向前后节点的指针,为的是最大限度的降低磁盘的IO;因为数据在内存中读取耗费的时间是从磁盘的IO读取的百万分之一

而Redis是 内存中读取数据,不涉及IO,因此使用了跳表;

35、JVM操作

1、jstat -gc pid

可以显示gc的信息,查看gc的次数,及时间。

2、 jstack

可以看到当前Jvm里面的线程状况

36、MySQL 分库分表

1.为什么要分表:

当一张表的数据达到几千万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了。分表的目的就在于此,减小数据库的负担,缩短查询时间。

多库多表

随着数据量增加也许单台DB的存储空间不够,随着查询量的增加单台数据库服务器已经没办法支撑。这个时候可以再对数据库进行水平区分。

MySQL单表太大后有一个问题是不好解决: 表结构调整相关的操作基本不在可能

37、乐观锁悲观锁的实现

乐观锁实现方式: 取出记录时,获取当前version 更新时,带上这个version 执行更新时, set version = newVersion where version = oldVersion 如果version不对,就更新失败

(1)数据库中添加version字段

(2)实体类添加version字段 并添加 @Version 注解

(3)元对象处理器接口添加version的insert默认值

悲观锁的实现

大多数情况下依靠数据库的锁机制实现

select ...for update

query.setLockMode("user",LockMode.UPGRADE)

38、JDK动态代理为什么一定要接口

JDK动态代理实际上是程序在运行中,根据被代理的接口来动态生成代理类的class文件,并加载class文件运行的过程

由于java的单继承,动态生成的代理类已经继承了Proxy类的,就不能再继承其他的类,所以只能靠实现被代理类的接口的形式,故JDK的动态代理必须有接口

===为何调用代理类的方法就会自动进入InvocationHandler 的 invoke()方法呢?===

在动态代理类的定义中,构造函数是含参的构造,参数就是我们invocationHandler 实例,而每一个被代理接口的方法都会在代理类中生成一个对应的实现方法,并在实现方法中最终调用invocationHandler 的invoke方法

39、AOP、IOC

Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。 Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。 Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。 Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。 Target(目标对象):织入 Advice 的目标对象.。 Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

=IOC=====

由Ioc容器来控制对象的创建,容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象

40、DEBUG

Debug把所有数据都当成字节处理,因此可以用它检查内存中任何地方的字节以及修改任何地方的字节

运行之后即驻留内存,利用BIOS和DOS环境,管理计算机,包括显示、修改存储器和寄存器等诸多操作功能。由于它可以寻访内存各处,所以无论是初始装入,还是后期载入的执行程序,都在其监控之中

41、TCP传输速度

传输速度=通告窗口*每一个数据包的大小/往返 延时

比如:

通告窗口=15

数据包大小=1040Byte

往返延时=30ms

则传输速度=151040/(300.001)=520KB/s=4.16Mbit/s

则带宽至少为4.16Mbit/s才能不发生拥塞。

42、单线程和多线程的区别

多线程的好处:

可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,

这样就大大提高了程序的效率。

多线程的不利方面:

线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;

多线程需要协调和管理,所以需要CPU时间跟踪线程;

线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;

线程太多会导致控制太复杂,最终可能造成很多Bug;

多线程与单线程的区别

单线程程序:只有一个线程,代码顺序执行,容易出现代码阻塞(页面假死)

多线程程序:有多个线程,线程间独立运行,能有效地避免代码阻塞,并且提高程序的运行性能

43、堆和栈的区别

(1)Java的堆是一个运行时数据区,类的对象从堆中分配空间。这些对象通过new等指令建立,通过垃圾回收器来销毁。

(2)堆的优势是可以动态地分配内存空间,需要多少内存空间不必事先告诉编译器,因为它是在运行时动态分配的。但缺点是,由于需要在运行时动态分配内存,所以存取速度较慢。

(1)栈中主要存放一些基本数据类型的变量(*byte,*short,**int,long,float,double,boolean,char)和对象的引用。

(2)栈的优势是,存取速度比堆快,栈数据可以共享。但缺点是,存放在栈中的数据占用多少内存空间需要在编译时确定下来,缺乏灵活性。

44、Java的半编译和半解释,C是编译型

1)解释性语言固有开销

2)字节码加载执行开销

7)GC巨大开销

10)动态链接开销

45、RDB和AOF

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。

①、优势

(1)RDB文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。

(2)生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。

(3)RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

②、劣势

RDB快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑。当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据。

每当有一个写命令过来时,就直接保存在我们的AOF文件中

1优点

(1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据。(2)AOF日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损。

(3)AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。

(4)AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据

2缺点

(1)对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大

(2)AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的

(3)以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。

46、操作系统:并发和并行

对于单核:多线程和多进程的多任务是在单cpu交替执行(时间片轮转调度,优先级调度等),属于并发

每个进程被分配一个时间段,称作它的时间片,即该进程允许进行的时间。如果在时间片结束时进程还在运行,则cpu将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则cpu当即进行切换。

对于多核:同一个时间多个进程运行在不同的机器上或者同一个机器不同核心上,或者是同一个时间多个线程能分布在同一机器的不同核心上(线程数小于内核数),属于并行。

47、CPU调度进程的算法

先来先服务(FCFS)

最短作业优先(SJF)

最短剩余时间优先(SRTN)

最高响应比优先(HRRN)==处理时间和等待时间

最高优先级调度

多级反馈队列调度

48、HTTP1.0和1.1区别

1 HTTP1.0和HTTP1.1的区别

所以在HTTP/1.1中改用了持久连接,就是在一次连接建立之后,只要客户端或者服务端没有明确提出断开连接,那么这个tcp连接会一直保持连接状态

1.1 长连接(Persistent Connection)

   HTTP1.1支持长连接和请求的流水线处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启长连接keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。HTTP1.0需要使用keep-alive参数来告知服务器端要建立一个长连接。

1.2 节约带宽

   HTTP1.0中存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能。HTTP1.1支持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,客户端接收到100才开始把请求body发送到服务器;如果返回401,客户端就可以不用发送请求body了节约了带宽。

1.3 HOST域

   在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname),HTTP1.0没有host域。随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都支持host域,且请求消息中如果没有host域会报告一个错误(400 Bad Request)。

1.4缓存处理

   在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。

1.5错误通知的管理

   在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

主礼物长宽

49、HTTP和HTTPS区别

  1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

  2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

  3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

  4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

证书、协议、端口、连接

一口正脸

50、短连接设计

用26+26个大小写字母+10个整数形成 62的七次幂这么多的短连接 然后跟面试官说现在互联网大概就40亿+url

所以可以完全囊括住 对原来长链接进行转十进制 再hash成相应的62进制的数即可.

Q:MySQL如何操作

A:分库进行保存 可以一个库存五万个url直到40亿都存完

Q:那你怎么找到相应的库呢

A:(巧了 面试前一天刚留意了一下分库查找) 把库分成num_1 num_2...num_x直到40亿url全保存完

然后我们拿到短连接后转成对应的十进制数 用十进制数模50000 商就是对应的库的number.

Q:ok 那你Redis要怎么存 k-v吗 k-v分别是什么

A:k是短连接 v是长链接 查找的时候直接根据k找到v再302临时重定向到长(原)url

51、谈谈LinkedHashMap和HashMap的区别

LinkedHashMap就是链表+散列表的结构,其底层采用了Linked双向链表来保存节点的访问顺序,所以保证了有序性。

52、mybatits # 和 $ 的区别

1.#{}是预编译处理,${}是字符串替换。 Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值; Mybatis在处理{}时,就是把时,就是把{}替换成变量的值。

2.使用#{}可以有效的防止SQL注入,提高系统安全性。 MyBatis排序时使用order by 动态参数时需要注意,用$而不是#

53、JDBC

1、加载JDBC驱动程序。

在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.lang.Class类的静态方法forName(String className)实现。成功加载后,会将Driver类的实例注册到DriverManager类中。

2、提供JDBC连接的URL。

连接URL定义了连接数据库时的协议、子协议、数据源标识。

书写形式:协议:子协议:数据源标识。

3、创建数据库的连接。

要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象, 该对象就代表一个数据库的连接。

使用DriverManager的getConnectin(String url , String username , String password )方法传入指定的欲连接的数据库的路径、数据库的用户名和 密码来获得。

4、创建一个Statement,要执行SQL语句,必须获得java.sql.Statement实例。

Statement实例分为以下3 种类型:

(1)执行静态SQL语句。通常通过Statement实例实现。

(2)执行动态SQL语句。通常通过PreparedStatement实例实现。

(3)执行数据库存储过程。通常通过CallableStatement实例实现。

5、执行SQL语句。

Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate 和execute

6、处理两种情况的结果。

(1)执行更新返回的是本次操作影响到的记录数。

(2)执行查询返回的结果是一个ResultSet对象。

ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些 行中数据的访问。

使用结果集(ResultSet)对象的访问方法获取数据。

7、关闭JDBC对象(关闭结果集-->关闭数据库操作对象-->关闭连接)

去连SS集资

54、原子类

原子更新基本类型类

使用原子的方式更新基本类型,Atomic包提供了以下3个类。

  • AtomicBoolean: 原子更新布尔类型。

  • AtomicInteger: 原子更新整型。

  • AtomicLong: 原子更新长整型。

我们取得了旧值,然后把要加的数传过去,调用getAndAddInt () 进行原子更新操作,实际最核心的方法是 compareAndSwapInt(),使用CAS进行更新。我们Unsafe只提供了3中CAS操作,


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部