被volatile修饰的变量保证Java内存模型中的可见性和有序性。
volaitle底层是通过内存屏障来实现可见性和有序性。内存屏障是一个CPU的指令,他的作用有两个,一是保证特定操作的执行顺序,二是保证某些变量的内存可见性。内存屏障告诉编译器和CPU,不管什么指令都不能和这条内存屏障指令重排序,另一个作用是强制刷出各种CPU的缓存资源,因此任何CPU上的线程都能读取到这些数据的最新版本。
Java提供了两种锁机制来控制多个线程对共享资源的互斥访问。
当HashMap的容量到达threshold时,需要进行动态扩容,将容量扩大为原来的两倍,然后将存储的数据进行rehash。
Semaphore信号量类似于操作系统的信号量,可以控制对互斥资源的访问线程数。
CPU和内存之间增加高速缓存。
所有的变量都存储在主内存中,每个线程有自己的工作内存,工作内存存储在高速缓存中,保存了该线程使用变量的拷贝。
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
8.Java内存空间是怎么分配的?
8.新生代和老年代可以转换吗?
对象优先分配在新生代的Eden区,通过长期存活(达到一定岁数)的对象进入老年代和动态对象年龄判定使对象从新生代进入老年代。
9.这些内存里面的垃圾怎么回收?
引用计数法和可达性分析法。回收算法包括:标记-清除、标记-整理、复制、分代收集算法。
10.怎么判断是垃圾?GCRoot可以为哪些?
可达性分析法中,从GC Root出发,不可达的是可以被回收的对象。
垃圾收集器都存在 Stop The World 的问题,G1对这个问题进行了优化,G1对整个新生代和老年代一起回收,把堆划分为多个大小相等的独立区域region,使得每个region可以单独进行垃圾回收,通过记录每个region垃圾回收时间以及回收所获得的空间(通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的region。
BIO,同步阻塞IO,一个线程处理一个连接,发起和处理IO请求都是同步的
NIO,同步非阻塞IO,一个线程处理多个链接,发起IO请求是非阻塞的,处理IO请求是同步的(轮询)
AIO,异步非阻塞IO,一个有效请求一个线程,发起和处理IO请求都是异步的。
当队列中没有元素时take()被阻塞,当队列满时put()被阻塞 |
大的计算任务拆分成小任务,并行计算 |
11.实现线程安全的方法
15.守护线程是什么?守护线程是怎么退出的?
守护线程是在程序运行时提供后台服务的线程,不属于程序运行中不可或缺的部分。
当程序中所有非守护线程结束时,程序也就终止,同时杀死所有的守护线程。
HashMap中使用一个技巧,和将哈希值与旧容量进行&运算,如果位上为0则在原位置,如果为1则在下边。
equals用来判断实体在逻辑上是否相等,当重写equals方法时要重写hashcode方法。
19.equals和==的区别?我要比较内容呢?
记录正在执行的虚拟机字节码指令的地址 | 栈帧用于存储局部变量表、操作数栈、常量池引用等信息 | 与JVM栈类似,为本地方法服务 | 对象分配区域,垃圾收集的主要区域 | 用于存访加载的类信息、常量、静态变量、即时编译器编译后的代码 | 方法区的一部分,存放生成的字面量和符号引用 |
需要(垃圾回收的主要区域) |
类的卸载:1.类实例被回收2.加载类的classloader被回收3.class对象没有被引用 方法区在jdk1.8以前放在永久代中,jdk1.8以后放在本地内存中,而不是JVM内存 |
标记-清除/标记-整理 |
只有在内存不够的情况下才会被回收 |
一定会被回收,只能存活到下一次垃圾回收发生之前 |
不会对其生存时间造成影响,唯一目的是在这个对象被回收时收到一个系统通知 |
标记要收集的对象,然后清除 | 标记和清除效率都不高,造成内存碎片 |
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存 | 对标记-清除算法的补充 |
将内存划分为相等的两块,每次只使用其中的一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后把使用过的内存空间进行一次清理 | |
他根据对象存活周期将内存划分为几块,不同块采用适当的收集算法。 一般将堆分为新生代和老年代。
|
动态调整以提供最合适的停顿时间或者最大吞吐量 | 注重吞吐量以及CPU资源敏感场合 |
注重吞吐量以及CPU资源敏感场合 | |
空间整合:基于 标记-整理 |
2. 老年代不足(大对象、长期存活的对象进入老年代) 3. 空间分配担保失败 |
1.简述TCP的三次握手、四次挥手,为什么要三次握手?为什么client会进入TIME_WAIT?
三次握手过程中主要对序号(seq)、确认序号(ack)、标志位(ACK、SYN)进行操作。
(4)server端收到确认后,连接建立
为什么要进行三次握手?
第三次握手时为了防止失效的连接请求到达服务器,让服务器错误打开连接。
客户端发送的连接请求如果在网络中滞留,那么就会隔很长时间才能收到服务器的连接确认。客户端等待一个超时重传时间后,就会重新发起请求。但是这个滞留的连接请求最后还是会到达服务器,如果不进行第三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打开连接。
客户端接收到服务器的FIN报文后进入TIME_WAIT状态而不是CLOSED,还需要等待2MSL,理由:
确保最后一个确认报文能够到达。如果server端没收到client端发来的确认报文,那么就会重新发送连接释放请求报文。
为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。
慢开始:最初,发送方只能发送一个报文段(假设),当收到确认后,将拥塞窗口(cwnd)加倍,呈指数型增长
拥塞避免:设置一个慢开始门限ssthresh,当cwnd>=ssthresh,进入拥塞避免,每个轮次只将cwnd加1
快重传:在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到M1和M2,此时收到M4,应该发送对M2的确认。在发送方,如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。
快恢复:在这种情况下,只是丢失个别报文段,不是网络拥塞,因此执行快恢复,令ssthresh=cwnd/2,cwnd=ssthresh,此时直接进入拥塞避免。
3.浏览器输入url请求服务器的过程,分析其中哪些部分用到缓存。
若浏览器缓存中未找到,查找本机host文件
若本机host文件中未找到,则查找路由器、ISP缓存
若路由器、ISP缓存中未找到,则向配置的DNS服务器发起请求查找(若本地域名服务器未找到,会向根域名服务器->顶级域名服务器->主域名服务器)
获取到url对应的ip后,发起TCP三次握手
发送http请求,将响应显示在浏览器页面中
4.ARP(地址解析协议)
ARP实现由IP地址得到MAC地址。
主机A知道主机B的IP地址,但是ARP高速缓存中没有该IP地址到MAC地址的映射,此时主机A通过广播的方式发送ARP请求分组,主机B收到该请求后会发送ARP响应分组给主机A告知其MAC地址,随后主机A向其高速缓存中写入主机B的IP地址到MAC地址的映射。
5.HTTP的流量控制,具体的控制算法
流量控制是为了控制发送方发送速率,保证接收方来得及接收。
接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。
6.计算机网络体系结构
为特定应用程序提供数据传输服务 | |||
为进程提供数据传输服务 | |||
路由器(路由选择和分组转发) 路由协议选择:RIP/OSPF(内部) |
IP协议(分类、子网划分、无分类) NAT:将本地IP转换为全球IP |
为主机提供数据传输服务 | |
地址解析协议(ARP):由IP地址得到MAC地址 |
|||
网际控制报文协议(ICMP):封装在IP数据包中,但不属于高层协议,是为了更有效地转发IP数据包和提高交付成功的机会。 |
|||
网际组管理协议(IGMP) |
|||
交换机(自学习交换表:MAC地址到接口的映射) | 一台主机有多少个网络适配器就有多少个MAC地址 | 广播信道(星型、环形、直线型) | 为同一链路的主机提供数据传输服务 |
在传输媒体上传输数据比特流 |
在向下的过程中,需要添加下层协议所需要的首部或者尾部,而在向上的过程中不断拆开首部和尾部。
基于距离向量的路由选择协议 | 每个自治系统必须配置BGP发言人,发言人之间通过TCP连接来交换路由信息 |
最大距离为15,限制了网络规模 |
只能寻找一条比较好的路由,而不是最佳路由 |
一对一、一对多、多对一和多对多 |
类似于浏览器输入url请求服务器的过程?
HTTPS 可以防窃听(非对称密钥加密)、防伪装、防篡改(加密和认证)
客户端发送请求到服务器端
服务器端返回证书和公开密钥,公开密钥作为证书的一部分而存在
客户端验证证书和公开密钥的有效性,如果有效,则生成共享密钥并使用公开密钥加密发送到服务器端
服务器端使用私有密钥解密数据,并使用收到的共享密钥加密数据,发送到客户端
客户端使用共享密钥解密数据
安全(不会改变服务器状态) |
1.mysql的索引,最左匹配原则
索引可以加快对数据的检索。常见的有B+Tree索引,哈希索引。
当索引是联合索引,在查询条件中,mysql是从最左边开始命中的,如果出现了范围查询(>、<、between、like),就不能进一步命中了,后续退化为线性查找,列的排列顺序决定了可命中索引的列数。
mysql为了保持高可用,会采用一主多从的结构,一个master节点,多个slave节点,master节点可以进行写操作,而slave节点只能进行读操作。
binlog线程:将主服务器上的数据更改写入二进制日志中
I/O线程:从主服务器上读取二进制日志,并写入从服务器的重放日志中
SQL线程:读取重放日志并重放其中的SQL语句
3.mysql的聚集索引、非聚集索引
聚集索引:以主键创建的索引,在叶子结点上存储的是表中的数据
非聚集索引:以非主键创建的索引,叶子结点上存储的是主键和索引列
使用非聚集索引查询出数据时,拿到叶子上的主键再去查到想要查找的数据。(回表)
4.mysql联合索引,要注意什么?
联合索引即索引由多个列(a,b,c,d)组成,要注意索引的命中,最左匹配原则,从左开始命中,遇到范围查询就不能进一步匹配。
5.为什么数据库要使用B+树来实现索引?
更少的查找次数(B+树相比红黑树更矮胖)
利用磁盘预读特性(一次IO能完全载入一个节点)
使用B+ Tree作为底层实现 |
对树进行搜索,查找速度快 分为聚簇索引和非聚簇索引 |
只支持精确查找,时间复杂度为O(1) |
当索引值使用的频繁时,会在B+ Tree索引之上再创建一个哈希索引 |
全文索引使用倒排索引实现,记录着关键词到其所在文档的映射 | |
9.MySQL数据库是怎么插入的?
10.事务怎么回滚?里面有什么日志?
11.一百万条数据记录,如何分页显示最后一条?
设一个列从1开始自增,并设为索引,以这个列为条件进行查询。
12.数据库事务隔离级别,可重复度和可串行化实现的原理
隔离级别:读未提交、读已提交、可重复度、串行化
1.数据库并发一致性问题
数据库并发一致性问题是由于隔离性导致的。
没开始一个事务,系统版本号+1 |
事务开始时的系统版本号 |
数据创建时的系统版本号 |
数据删除时的系统版本号 |
每个非主属性完全依赖于键码 |
每个非主属性不传递函数依赖于键码 |
1.B+树和B树的区别
B+树的数据都在叶子结点上,而B树的非根非叶节点也是数据节点,所以B+树的查询更稳定。
B+树有两个指针,一个指向root节点,一个指向叶子节点的最左侧,因此其范围查询效率更高,而B树则需要中序遍历B树。
同阶的情况下,B+树节点中的关键字要比B树多一个,并且B+树的中间节点不保存数据,所以磁盘也能够容纳更多结点元素,因此B+树更加矮胖,查询效率也更高。
红黑树是一个自平衡二叉查找树。时间复杂度O(log n)
3.红黑树和平衡二叉树的区别
平衡二叉树和高度相关,保持平衡的代价更高(多次旋转),因此适用于插入、删除较少,查询较多的场景。
红黑树和高度无关,旋转次数较少,因此适用于插入、删除较多的场景。
3.Spring IOC里面的反射机制怎么实现的?
1.redis分片,客户端请求怎么处理?
Redis的分片是指将数据分散到多个Redis实例中的方法,分片之后,每个redis拥有一部分原数据集的子集。在数据量非常大时,分片能将数据量分散到若干主机的redis实例上,进而减轻单台redis实例的压力。
跳跃表相比于红黑树的优点:
redis为单进程单线程模式,采用队列模式将并发访问变为串行访问,redis本身没有锁的概念,但可以用redis实现分布式锁。
分布式锁的核心思想是将设置锁和超时时间、删除锁分别作为一个原子操作进行。
6.redis无法被命中怎么办?会出现什么问题?
无法被命中:无法直接通过缓存得到想要的数据
三个线程(binlog线程、I/O线程、SQL线程),目的是实现读写分离 |
使用RDB快照进行复制,发送期间使用缓冲区记录执行的写命令,在RDB快照发送完毕后,发送缓冲区中的写命令 |
8.Redis是什么?Sorted List是什么?skiplist是什么?怎么实现的?怎么插入一个值?怎么进行查询?和其他数据结构进行对比?
2.可达性分析算法的root
可达性分析算法是从GC root出发,只有通过GC root可达的对象是被引用的对象,不可达的对象属于可以回收的对象。
2.操作系统的内存管理
3.分页式的页表放在哪
进程控制块(PCB)中。
4.进程的PCB里还有哪些东西?
5.MMU(内存管理单元)
内存管理单元(MMU)管理着地址空间和物理内存的转换,根据其内存管理方式的不同,其中包括基地址寄存器、界限地址寄存器的值以及段表和页表。
采用共享内存的进程间通信需要通信进程建立共享内存区域。通常一块共享内存区域驻留在生成共享内存段的进程的地址空间。需要使用信号量用来同步对通向存储的访问。
9.应用程序是如何读取文件的?
1.linux脚本,杀掉包含一个关键字的所有进程
都属于linux内核中的内核锁。
互斥锁通过对共享资源的锁定和互斥解决利用资源冲突问题,互斥锁是选择睡眠的方式来对共享工作停止访问的。
自旋锁不会引起调度者睡眠,而是一直循环。
应用进程被阻塞,知道数据从内核缓冲区复制到应用进程缓冲区才返回 | 阻塞期间,其他进程继续执行,CPU利用率高 |
多次执行系统调用,CPU利用率低 | |
单个线程具有处理多个I/O时间的能力 | |
执行系统调用后立即返回,内核在数据到达时向应用进程发送SIGIO信号,应用进程收到后将数据从内核复制到应用进程 | CPU利用率比非阻塞I/O高 |
系统调用立即返回,不会阻塞,内核完成所有操作后向应用进程发送信号 |
异步I/O通知应用进程I/O完成 信号驱动I/O是通知应用进程可以开始I/O |
数组(因此有最大限制) |
准备好的描述符加入到一个链表中管理 |
描述符多,描述符变化小 |
在分布式系统中,分区容忍性必不可少,因为需要总是假设网络是不可靠的。因此,CAP理论实际上是要在可用性和一致性做权衡。
BASE理论是对CAP中一致性和可用性权衡的结果,它的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
ACID要求强一致性,通常运用在传统的数据库系统上。而BASE要求最终一致性,通过牺牲强一致性来达到可用性,通常运用于大型分布式系统中。
(1)两阶段提交(2PC)
存在问题:1.同步阻塞 2.单点问题 3.数据不一致 4.太过保守
针对每个操作,都要注册一个与其对应的确认和补偿操作
(3)本地消息表(异步确保)
将业务操作和本地消息表放在一个事务中。业界使用最多。
事件溯源,相当于将分布式系统中的操作都记录到数据库日志表中,要获得最新的状态,则需要重新执行一遍日志表的操作。并且可以dump某一时刻的数据表,在此基础上执行在这之后的操作。
1.二叉树的先序遍历,层序遍历的实现
3.包括max函数的栈
4.找一个n*n矩阵的最长上升序列
5.快速排序,什么时候复杂度最大
8.给你一个数组,数组长度为n。请找出数组中第k大的数
附加条件:不允许改变元素在数组中的位置
在int范围内去中位数,算出其在数组中是第几大的元素(遍历数组O(n)),与k比较不断二分。
9.找到数据流中的中位数
使用大小顶堆,如果放入的是奇数个,则取大顶堆的根结点,如果是偶数个则取大小顶堆根结点的平均值。
10.删除链表中重复节点
11.给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
12.给定过一个二叉树,原地将它展开为链表
13.给定一个二叉树,想象自己站在他的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
11.判断是否是二叉搜索树
12.合并两个链表,用递归和非递归实现
13.字符串是否为给定字符串的子串
14.查找两个链表的公共节点
16.一个数x,一个数n,x中删n位使得剩下的数最大
17.给定一颗二叉树,求其中root的最长路径。所谓路径是指,联通两个节点的最小边数。
18.二叉树的序列化与反序列化
本文由作者供稿,作者是一名非本专科非本班级的大三学生。以下是他最近接受采访的摘要:
先说说我的面试准备经历。为了保证简历有大概率通过筛选,我在去年11月面试了很多公司,到一家小公司实习到今年3月。