1、重定向的状态码
https://blog.51cto.com/wiigood/929619
2xx (成功):::表示成功处理了请求的状态码
3xx (重定向):::要完成请求,需要进一步操作
4xx(请求错误):::这些状态码表示请求可能出错,妨碍了服务器的处理
301 Moved Permanently(永久移动):被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个URI之一。
302 Found(发现):要求客户端执行临时重定向(原始描述短语为“Moved Temporarily”)。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。
200 OK:请求成功
301 Permanently:永久重定向,表示请求的资源已经永久的搬到了其他位置。
302 Found:临时重定向,表示请求的资源临时搬到了其他位置。
304(未修改)自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
400 Bad Request:表示请求报文存在语法错误或参数错误,服务器不理解。
403 Forbidden:服务器已经理解请求,但是拒绝执行它。
404 Not Found:请求失败,服务器找不到请求的资源。
500 Internet Server Error:服务器出错了。
502(错误网关)服务器作为网关或代理,从上游服务器收到无效响应
503 Service Unavailable:服务器没有准备好处理请求。
504(网关超时)服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505(HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
2、Linux的进程调度
3、零拷贝
4、Nginx的线程模型
5、多线程有序打印1和2,分别打印10次
6、数据库表的优化
****通过拆分表提高表的访问效率
对数据表的拆分,分为两种拆分方式:垂直拆分,水平拆分
1.垂直拆分(分表)
即把主键和一些数据表的列放在一个表中,然后把主键和另一些数据表的列放在一个表中。
如果一个表的某些列常用,另一些不常用,则可以采用垂直拆分。垂直拆分可以使数据行变小,一个数据页就可以存放更多的数据,在查询时候可以减少I/O次数。其缺点是需要管理冗余列,查询所有数据时候需要join查找。
2.水平拆分(分表,分区)
即把数据表中的列根据一定规则放在多个独立的表或分区中。
****选择合适的数据类型
****适度冗余:把需要join的项写到一个表中,这样可以减少join的次数
7、CMS和G1的区别
****区别一: 使用范围不一样
CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用
G1收集器收集范围是老年代和新生代。不需要结合其他收集器使用
****区别二: STW的时间
CMS收集器以最小的停顿时间为目标的收集器。
G1收集器可预测垃圾回收的停顿时间(建立可预测的停顿时间模型)
****区别三: 垃圾碎片
CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片
G1收集器使用的是“标记-整理”算法,进行了空间整合,降低了内存空间碎片。
****区别四: 垃圾回收的过程不一样
CMS收集器 G1收集器
- 初始标记 1.初始标记
- 并发标记 2. 并发标记
- 重新标记 3. 最终标记
- 并发清除 4. 筛选回收
CMS过程:
****初始标记:这个阶段是标记从GcRoots直接可达的老年代对象、新生代引用的老年代对象。这个过程是单线程的。
****并发标记:由上一个阶段标记过的对象,开始tracing过程,标记所有可达的对象,这个阶段垃圾回收线程和应用线程同时运行。
****重新标记:为了修正并发标记期间因用户程序继续运作而导致标记变动的那一部分对象的标记记录。
***并发清除:回收所有的垃圾对象,整个过程中耗时最长的并发标记和并发清除都可以与用户线程一起工作,所以总体上说,CMS收集器的内存回收过程与用户线程一起并发执行。
CMS优缺点:
CMS是一款“标记–清除”算法实现的收集器,容易出现大量空间碎片;CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程而导致应用程序变慢,总吞吐量会降低。
并发收集,低停顿
8、手写Map的实现
9、进程如何创建?(底层实现。。。)
10、线程如何创建?(底层实现。。。)
11、线程如何互斥
设立临界区,并通过锁机制
12、锁有哪几种
公平锁/非公平锁、可重入锁与非可重入锁、乐观锁/悲观锁、共享锁/排它锁
13、快排时间复杂度?最差呢?优化?
最差情况下是O(nn),可以采用随机选取法应对最差情况。
14、设计一个数据结构,有(0-9亿)条数据,支持FIFO、LIFO,4G memory。要求动态设定长度,不能超出内存限制。
充分考虑空间因素,适当动态分配空间和删除空间即可,因此可以利用双向链表加数组来实现。
15、悲观锁和乐观锁的具体实现原理,CAS算法及ABA问题
Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
乐观锁采用版本号机制:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。
乐观锁采用CAS算法:CAS是一种无锁算法,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
i++ 的原子性问题:int i=i++ 的操作实际上分为三个步骤“读-改-写”
第一步:int temp = i;
第二步:i = i + 1;
第三步:i = temp;
缺点:循环时间长开销大:自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销
缺点:只能保证一个共享变量的原子操作
缺点:ABA 问题:如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。
案例:
小明账户上有100元。现在小明取钱,小强汇钱,诈骗分子盗刷三个动作同时进行。1,小明取50元。2,诈骗分子盗刷50元。3,小强给小明汇款50元。此时,银行交易系统出问题,每笔交易无法通过短信告知小明。ABA问题就是:1,小明验证账户上有100元后,取出50元。——账上有50元。2,小强不会验证小明账户的余额,直接汇款50元。——账上有100元。3,诈骗分子验证账户有100元后,取出50元。——账上有50元。小强没有告诉小明自己汇钱,小明也没收到短信,那么小明就一直以为只有自己取款操作,最后损失了50元。
解决办法:加上一个版本号
16、几千万条数据,存在外存里,你如何找到最大的前100条,综合考虑时间和空间复杂度
https://juejin.im/entry/5a27cb796fb9a045104a5e8c
17、负载均衡算法
轮询法:将请求按照顺序轮流的分配到服务器上,他均衡的对待每一台后端的服务器,不关心服务器的的连接数和负载情况.以下代码演示了这种算法。
随机法:通过系统的随机函数,根据后端服务器列表的大小来随机获取其中的一台来访问,随着调用量的增大,实际效果越来越近似于平均分配到没一台服务器.和轮询的效果类似。
源地址hash法:源地址hash法的思想是获取客户端访问的ip地址,通过hash函数计算出一个hash值,用该hash值对服务器列表的大小进行取模运算,得到的值就是要访问的服务器的序号。
18、对象的生命周期
创建阶段、应用阶段(对象至少被一个强引用持有着)、不可见阶段(程序本身不再持有该对象的任何强引用)、不可达阶段(对象处于不可达阶段是指该对象不再被任何强引用所持有)、收集阶段
19、布隆过滤器
应用场景:在网络爬虫里,一个网址是否被访问过,yahoo, gmail等邮箱垃圾邮件过滤功能,即如何判断一个元素是否存在一个集合中。
方法:
假设集合里面有3个元素{x, y, z},哈希函数的个数为3。首先将位数组进行初始化,将里面每个位都设置位0。对于集合里面的每一个元素,将元素依次通过3个哈希函数进行映射,每次映射都会产生一个哈希值,这个值对应位数组上面的一个点,然后将位数组对应的位置标记为1。查询W元素是否存在集合中的时候,同样的方法将W通过哈希映射到位数组上的3个点。如果3个点的其中有一个点不为1,则可以判断该元素一定不存在集合中。反之,如果3个点都为1,则该元素可能存在集合中。注意:此处不能判断该元素是否一定存在集合中,可能存在一定的误判率。可以从图中可以看到:假设某个元素通过映射对应下标为4,5,6这3个点。虽然这3个点都为1,但是很明显这3个点是不同元素经过哈希得到的位置,因此这种情况说明元素虽然不在集合中,也可能对应的都是1,这是误判率存在的原因。
20、NIO、bio/nio/aio
21、JMM
Java内存模型规定了所有的变量都存储在主内存(Main Memory)中,每个线程还有自己的工作内存(Working Memory),线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝。主内存主要对应Java堆中的对象实例数据部分,工作内存则对应虚拟机栈的部分区域。
22、JVM 运行时候数据模型是怎么样的
24、实现热加载主要解决了什么问题
25、栈内存为什么要用栈结构
栈内存一般存储的是函数的调用信息和函数中申明的变量,因为函数的调用是递归的,外层函数一定比内层被调用的函数先加载和执行,而一定等到内层被调用函数结束后才能结束,这个先进后出的机制就是为什么叫栈内存的原因。
27、TCP连接是什么
是TCP控制块,告知彼此的第一个发送字节的初始***,建立连接后对每一个发送的字节都需要以初始***为原点进行编号,需要对方来确认每一个字节编号都已经成功接收,此乃建立连接的本质。
29、联合索引什么时候不会生效
mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描;不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
30、Redis有几种数据结构?排序集合怎么实现的?跳表怎么实现的
有序集合的编码可以是 ziplist 或者 skiplist 。
ziplist 编码的有序集合对象使用压缩列表作为底层实现, 每个集合元素使用两个紧挨在一起的压缩列表节点来保存, 第一个节点保存元素的成员(member), 而第二个元素则保存元素的分值(score)。压缩列表内的集合元素按分值从小到大进行排序, 分值较小的元素被放置在靠近表头的方向, 而分值较大的元素则被放置在靠近表尾的方向。
有序集合可以单独使用字典或者跳跃表的其中一种数据结构来实现, 但无论单独使用字典还是跳跃表, 在性能上对比起同时使用字典和跳跃表都会有所降低。
31、数据库的脏读和幻读?如何解决、可重复读和串行化实现的原理,InnoDB 默认是什么级别?可重复读会加读锁吗?提交读会加吗?为什么?
四种隔离级别就是脏读、不可重复读和幻读的解决方法
脏读:A对数据进行了修改,但未提交,B读取了未提交的数据
不可重复读:A读取了两次,但B在两次之间进行了修改,故A读取的数据前后不一致。
幻读:A对整个表进行了修改,B对其中某些数据进行了修改。A读取的前后数据量不一致
措施:
READ_UNCOMMITED 的原理:
事务对当前被读取的数据不加锁;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加行级共享锁,直到事务结束才释放。
READ_COMMITED 的原理:
事务对当前被读取的数据加 行级共享锁(当读到时才加锁),一旦读完该行,立即释放该行级共享锁;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。
REPEATABLE READ 的原理:
事务在读取某数据的瞬间(就是开始读取的瞬间),必须先对其加 行级共享锁,直到事务结束才释放;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。
SERIALIZABLE 的原理:
事务在读取数据时,必须先对其加 表级共享锁 ,直到事务结束才释放;
事务在更新数据时,必须先对其加 表级排他锁 ,直到事务结束才释放。
由于 B+ 树分支比二叉树更多,所以相同数量的内容,B+ 树的深度更浅,深度代表什么?代表磁盘 io 次数啊!数据库设计的时候 B+ 树有多少个分支都是按照磁盘一个簇上最多能放多少节点设计的啊!所以,涉及到磁盘上查询的数据结构,一般都用 B+ 树啦。
33、不可变类,机制,实现原理
不可变类(Immutable Class):所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值。如JDK内部自带的很多不可变类:Interger、Long和String等。
可变类(Mutable Class):相对于不可变类,可变类创建实例后可以改变其成员变量值,开发中创建的大部分类都属于可变类。
方法:使用private final修饰,不提供setter方法
优点:
线程安全:不可变对象是线程安全的,在线程之间可以相互共享,不需要利用特殊机制来保证同步问题,因为对象的值无法改变。可以降低并发错误的可能性,因为不需要用一些锁机制等保证内存一致性问题也减少了同步开销。
易于构造、使用和测试
34、数据库的回滚与日志
35、IOC的反射机制是怎么实现的
36、
用户线程:我们平常创建的普通线程。
守护线程:用来服务于用户线程;不需要上层逻辑介入
当主线程结束时,结束其余的子线程(守护线程)自动关闭,就免去了还要继续关闭子线程的麻烦。如:Java垃圾回收线程就是一个典型的守护线程;内存资源或者线程的管理,但是非守护线程也可以。
37、守护线程怎么退出的
38、锁的开销
这样我们大致可以把锁冲突的开销分成三部分,“纯上下文切换”开销,大概是150ns,调度器开销(把线程从睡眠变成就绪或者反过来)大概是900ns,在多核系统上,还存在跨处理器调度的开销,那部分开销很大,超过2000ns。在真实的应用场景里,还要考虑上下文切换带来的cache不命中和TLB不命中的开销,开销只会进一步加大。
39、ConcurrentHashMap实现的原理
41、post和delete区别
DELETE请求顾名思义,就是用来删除某一个资源的,该请求就像数据库的delete操作。
44、HTTP数据量很大,怎么发送
45、大文本数据(数T),统计每个字符串的频率
46、进程间通信和线程间通信的区别
线程间资源是共享的,讲安全:信号量,锁,原子操作;进程间资源是独立的,讲通讯:管道,共享内存。
线程间通信:由于多线程共享地址空间和数据空间,所以多个线程间的通信是一个线程的数据可以直接提供给其他线程使用,而不必通过操作系统(也就是内核的调度)。进程间的通信则不同,它的数据空间的独立性决定了它的通信相对比较复杂,需要通过操作系统。以前进程间的通信只能是单机版的,现在操作系统都继承了基于套接字(socket)的进程间的通信机制。这样进程间的通信就不局限于单台计算机了,实现了网络通信。
47、TCP server最多可以建立多少个TCP连接
因此最大tcp连接为客户端ip数×客户端port数,对IPV4,不考虑ip地址分类等因素,最大tcp连接数约为2的32次方(ip数)×2的16次方(port数),也就是server端单机最大tcp连接数约为2的48次方。
48、Linux 查看内存
49、一个进程,有十个线程,其中一个线程fork后,子进程有几个线程
fork后子进程只能有一个线程
50、计算机冷启动,内存和寄存器怎么加载的
第一阶段:BIOS阶段
第二阶段:确定**分区
第三阶段:确定操作系统的位置
第四阶段:加载操作系统内核到内存中
后操作系统内核完成系统的初始化,并允许用户与操作系统进行交互
53、跳表的增删查时间复杂度
54、 trie树(字典树)
根节点不包含字符,除根节点外每一个节点都只包含一个字符。从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。每个节点的所有子节点包含的字符都不相同。
b,abc,abd,bcd,abcd,efg,hii 这6个单词,我们构建的树就是如下图这样的:
插入和查询时间复杂度都为 O(k) ,其中 k 为 key 的长度,Trie 的缺点是空间消耗很高。
55、接口与抽象类区别
56、多态的类型
57、spring beans单例和多例使用条件
58、b+树比红黑树好在哪里
59、数据库是怎么在磁盘上查询数据的
60、select、poll和epoll以及几种模型的实际应用
61、url—6位短地址的映射,lru算法
62、实现Java的RLock WLock RULock UWLock
63、用Java实现一个信号量
65、MySQL RR级别(这里面试官说这个是读已提交,其实是可重复读repeatable read)能否保证同一个事务的多次范围查询结果相同
66、jvm 的局部变量表是做什么的?
存储局部变量、函数调用时传递参数,很多字节码指令都是对局部变量表和操作数栈进行操作的。
方法区的数据引用、当前代码处的局部变量,基本就是用户能通过代码引用到的。
68、说一下建表时,建索引有哪些要注意的
选区分度比较大的,选数据类型比较小的比如整数而不要选长字符串,选where子句中出现的
70、效率比较低,怎么解决
分段锁:有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争
71、线程池的链表
线程池里的阻塞队列,似乎都是用链表实现的,没有用数组。用到的队列似乎默认都是动态扩容的,最大为整数最大值。如果队列满了又不支持动态扩容,可以通过设置饱和策略来处理,默认是中止,也就是抛出 RejectedExecutionException。
72、保证并发计数正确
原子变量,于是说 AtomicInteger,因为用了CAS算法
74、
如果有多个变量要更新,要保证一致性,怎样加锁来保证正确性,效率又比较高?只在写时加锁,读不加锁
75、适配器模式呢?
了解设计模式各个模式的含义,IOC用到了哪些设计模式
76、io为什么会阻塞、nio的底层实现原理、nio 为什么是非阻塞的
77、arrayList如何动态扩展
而是将现有的个数乘以2,然后将原来的元素复制过去。当数据容不下时,ArrayList会再创建一个更大的数组,数组长度为之前所说的那样,然后将之前的数据拷贝到新数组中。这就是ArrayList基于数组实现的可变长度原理。
78、为什么hashmap线程不安全,如何保证hashmap线程安全,ConcurrentHashMap与HashMap的区别、ConcurrentHashMap是如何实现线程安全的(CAS,当时忘了),写代码:实现一个 hashtable
put的时候导致的多线程数据不一致。线程A再次被调度运行时,它依然持有过期的链表头但是它对此一无所知,以至于它认为它应该这样做,如此一来就覆盖了线程B插入的记录,这样线程B插入的记录就凭空消失了,造成了数据不一致的行为。
如何保证:
使用Hashtable、ConcurrentHashMap
79、gc发生的时间、gc root节点的种类,什么可以作为GCRoot,GCroot可以为哪些?
方法区的数据引用、当前代码处的局部变量,基本就是用户能通过代码引用到的。
答:a. java虚拟机栈(栈帧中的本地变量表)中的引用的对象。
b.方法区中的类静态属性引用的对象。
c.方法区中的常量引用的对象。
d.本地方法栈中JNI本地方法的引用对象。
80、挥手时,不通知应用层把程序关掉会怎么样
81、生产者消费者模型的实现(堵塞队列,代码)
82、Linux查看CPU核数命令、PING命令(少许错误) 、top命令
83、url各部分是什么,结合后端举例回答、url里的参数encode是什么作用
84、http结构
85、Java堆和栈详谈
86、Java代码编译过程
87、JIT是什么,作用
88、索引有哪几种? (先说的底层B+tree和Hash等,面试官说先不说底层,说平时使用的索引)
89、JVM详解,JMM相关
90、order by 能用到索引吗
91、画一下整个后端的操作流程?有什么可以优化的地方?安全性的角度?为什么要加密?
92、设计一个支持售卖(A 到 B 站)和余票查询的功能,再写出功能的 sql 语句
93、索引为abc且查询条件为a=xxx order by b时能用上哪个索引
94、urlencode是什么
95、java线程池添加任务的过程,一致性哈希是什么
96、一道大数据量的题目,A文件有3T,里面放的是uid+uname,B文件2T,里面放的是uid+unage,找出相同的uid并写成uid+uname+uage的样子,限制内存2G
97、如何实现分布式锁
98、redis和java中原子类自增怎么是实现
100、智力题,从1走到n,可以向前和向后,第k步走k个步长,求要多少步走到结尾
102、equals和==的区别?我要比较内容呢?
答:equals:是用来比较两个对象内部的内容是否相等的。
:是用来判断两个对象的地址是否相同,即是否是指相同一个对象。
如果没有重写equals时,是直接用判断的
如果是基本类型和基本型封装,则仍然为比较内容。
103、java的jar包是源代码吗?
jar包就是一堆.class文件
104、java的编译是怎么一个过程呢?
答:java编译器的话经过四个步骤,词义分析,语义分析,语法分析和代码生成。
105、java 的虚函数是怎么样的?
答:java里面是抽象函数和接口
106、java内存空间是怎么分配的?
一, 对象优先在新生代Eden区分配
二, 大对象直接进入老年代
三, 长期存活对象将进入老年代(虚拟机设计了一个对象年龄计数器,该阀值默认为15)
四, 动态对象年龄判定 如果Survivor区中相同年龄所有对象大小的总和大于Survivor区空间的一半,年龄大于或等于该年龄的对象在Minor GC时将复制至老年代
五, 空间分配担保 当Minor GC时如果存活对象过多,无法完全放入Survivor区,就会向老年代借用内存存放对象,以完成Minor GC