本文主要是介绍2020年五月份面试题总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
面试题总结
- 1. OSI(开放式系统互联通信参考模型)七层网络模型以及每一层有哪些协议
- 2. TCP和UDP的区别,分别在什么场景下使用
- 3. TCP的拥塞控制机制,滑动窗口的大小调整
- 4. 如何既想达到UDP的传输效果,又让连接是可靠的
- 5. Http是哪一层的协议,Https呢?
- 6. TCP、Http、Https连接过程
- TCP的三次挥手和四次挥手
- 三次挥手(建立连接)
- 四次挥手(断开连接)
- HTTP请求过程
- HTTPS
- 7. Https中使用到jwt和非jwt,为什么会使用到两种加密方式?(提示:性能问题)
- 8. 浏览器访问新浪网网址,经过了哪些过程?
- 9. 为什么会有InnoDB引擎和MyISAM引擎什么时候用MyISAM引擎?
- 10. MySql的四种事务隔离级别,每种隔离级别解决了什么问题?
- 11. Mysql的可重复读隔离级别是如何解决幻读问题的?
- 12. MySql的索引类别?聚集索引和非聚集索引是什么?有什么区别?什么场景下使用?
- 13. 数据库读写分离
- 14. jdk1.8对ConcurrentHashMap加了哪些新特性
- 15. 说一下JVM中你了解哪些知识
- 15.1 垃圾回收算法:
- 15.2 垃圾收集器
- 15.2.1 CMS
- 15.2.2 G1
- 16. Linux如何查看当前进程内存状况及使用情况
- 17. JVM的内存结构
- 17.1 线程共享的
- 17.2 线程独占的
- 18. 类加载
- 19. ThreadLocal和Synchronized
- 20. java的动态代理
- 21. java单例模式:
- 22. JWT(JSON WEB TOKEN)
- Header
- playload
- signature
- 23. Redis
- 24. Mysql执行流程
- 25. Map的有序存储
1. OSI(开放式系统互联通信参考模型)七层网络模型以及每一层有哪些协议
OSI将计算机网络体系结构(architecture)划分为以下七层:
-
物理层: 将数据转换为可通过物理介质传送的电子信号 相当于邮局中的搬运工人。
协议:EIA/TIA-232, EIA/TIA-499,V.35, V.24,RJ45, Ethernet, 802.3
-
数据链路层: 决定访问网络介质的方式。
在此层将数据分帧,并处理流控制。本层指定拓扑结构并提供硬件寻址,相当于邮局中的装拆箱工人。
协议:Frame Relay,HDLC,PPP, IEEE 802.3/802.2
-
网络层: 使用权数据路由经过大型网络 相当于邮局中的排序工人。
协议:IP,IPX,AppleTalk DDP
-
传输层: 提供终端到终端的可靠连接 相当于公司中跑邮局的送信职员。
协议:TCP,UDP,SPX
-
会话层: 允许用户使用简单易记的名称建立连接 相当于公司中收寄信、写信封与拆信封的秘书。
协议:RPC,SQL,NFS,NetBIOS,names,AppleTalk
-
表示层: 协商数据交换格式 相当公司中简报老板、替老板写信的助理。
协议:TIFF,GIF,JPEG,PICT,ASCII,EBCDIC,encryption
-
应用层: 用户的应用程序和网络之间的接口。
协议:FTP,WWW,Telnet,NFS,SMTP,Gateway,SNMP
2. TCP和UDP的区别,分别在什么场景下使用
- TCP是面向连接的(如打电话要先建立连接),UDP是无连接的,即发送数据之前不需要建立连接;
- TCP提供可靠的服务。也就是说,通过TCP连接传输的数据,无差错、不丢失、不重复、且按序到达;UDP尽最大努力交付,即不保证可靠交付;
- TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的,UDP没有拥塞控制,因此网络发生拥塞也不会使源主机的发送效率降低(对实时应用很有用,如IP电话、实时视频会议等);
- 每一条TCP的连接都是点对点的;UDP支持一对一、一对多、多对一和多对多的交互通信;
- TCP的首部开销20字节;UDP的首部开销相对较少,只有8字节;
- TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道;
总结:UDP效率高,速度快,不安全,支持一对多、多对多等优点。TCP效率低,速度慢,安全,只支持点对点连接;一般TCP用在对数据准确性要求高以及对安全性要求较高的场景下使用,UDP用在对准确性要求低,对效率要求较高的场景。
3. TCP的拥塞控制机制,滑动窗口的大小调整
拥塞控制是为了防止发送方发送的太快,网络来不及处理,从而导致网络拥塞的情况;
滑动窗口协议:是对TCP协议的一种应用,用于网络传输时的流量控制,以避免阻塞的发生。该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输,提高网络吞吐量。
4. 如何既想达到UDP的传输效果,又让连接是可靠的
UDP它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
传输层无法保证数据的可靠传输,只能通过应用层来实现了。实现的方式可以参照tcp可靠性传输的方式,只是实现不在传输层,实现转移到了应用层。
实现确认机制、重传机制、窗口确认机制。
如果你不利用linux协议栈以及上层socket机制,自己通过抓包和发包的方式去实现可靠性传输,那么必须实现如下功能:
发送:包的分片、包确认、包的重发
接收:包的调序、包的序号确认
目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT。
-
RUDP
RUDP 提供一组数据服务质量增强机制,如拥塞控制的改进、重发机制及淡化服务器算法等,从而在包丢失和网络拥塞的情况下, RTP 客户机(实时位置)面前呈现的就是一个高质量的 RTP 流。在不干扰协议的实时特性的同时,可靠 UDP 的拥塞控制机制允许 TCP 方式下的流控制行为。
-
RTP
实时传输协议(RTP)为数据提供了具有实时特征的端对端传送服务,如在组播或单播网络服务下的交互式视频音频或模拟数据。应用程序通常在 UDP 上运行 RTP 以便使用其多路结点和校验服务;这两种协议都提供了传输层协议的功能。但是 RTP 可以与其它适合的底层网络或传输协议一起使用。如果底层网络提供组播方式,那么 RTP 可以使用该组播表传输数据到多个目的地。
RTP 本身并没有提供按时发送机制或其它服务质量(QoS)保证,它依赖于底层服务去实现这一过程。 RTP 并不保证传送或防止无序传送,也不确定底层网络的可靠性。 RTP 实行有序传送, RTP 中的序列号允许接收方重组发送方的包序列,同时序列号也能用于决定适当的包位置,例如:在视频解码中,就不需要顺序解码。
-
UDT
基于UDP的数据传输协议(UDP-basedData Transfer Protocol,简称UDT)是一种互联网数据传输协议。UDT的主要目的是支持高速广域网上的海量数据传输,而互联网上的标准数据传输协议TCP在高带宽长距离网络上性能很差。顾名思义,UDT建于UDP之上,并引入新的拥塞控制和数据可靠性控制机制。UDT是面向连接的双向的应用层协议。它同时支持可靠的数据流传输和部分可靠的数据报传输。由于UDT完全在UDP上实现,它也可以应用在除了高速数据传输之外的其它应用领域,例如点到点技术(P2P),防火墙穿透,多媒体数据传输等等。
5. Http是哪一层的协议,Https呢?
Http属于应用层协议;
HTTPS和HTTP的区别主要为以下四点:
- https协议需要到ca申请证书,一般免费证书很少,需要交费。
- http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
6. TCP、Http、Https连接过程
TCP的三次挥手和四次挥手
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SrcGmiNo-1588820234910)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200429110043150.png)]
三次挥手(建立连接)
- 第一次:建立连接时,客户端发送SYN包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
- 第二次:服务器收到SYN包,向客户端返回ACK(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RCVD状态;
- 第三次:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
- 完成三次握手,客户端与服务器开始传送数据,也就是ESTABLISHED状态。
- 三次握手保证了不会建立无效的连接,从而浪费资源。
四次挥手(断开连接)
- 第一次: TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
- 第二次:服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
- 第三次:服务器关闭客户端的连接,发送一个FIN给客户端。
- 第四次:客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
HTTP请求过程
- 建立连接完毕以后客户端会发送响应给服务端
- 服务端接受请求并且做出响应发送给客户端
- 客户端收到响应并且解析响应响应给客户
HTTPS
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aJlD8awu-1588820234911)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200429105729589.png)]
- 在使用HTTPS是需要保证服务端配置正确了对应的安全证书
- 客户端发送请求到服务端
- 服务端返回公钥和证书到客户端
- 客户端接收后会验证证书的安全性,如果通过则会随机生成一个随机数,用公钥对其加密,发送到服务端
- 服务端接受到这个加密后的随机数后会用私钥对其解密得到真正的随机数,随后用这个随机数当做私钥对需要发送的数据进行jwt
- 客户端在接收到加密后的数据使用私钥(即生成的随机值)对数据进行解密并且解析数据呈现结果给客户
- SSL加密建立
7. Https中使用到jwt和非jwt,为什么会使用到两种加密方式?(提示:性能问题)
jwt:加密解密用的是同样的密钥;
非jwt:分为公钥和私钥,公钥用于加密,私钥用于解密;
jwt性能比非jwt要快的多,至少有1000倍;
8. 浏览器访问新浪网网址,经过了哪些过程?
- 通过域名定位到访问的IP
- 与服务器建立连接
- 发送请求
- 等待服务器的响应
- 接收响应
9. 为什么会有InnoDB引擎和MyISAM引擎什么时候用MyISAM引擎?
区别:
事务处理:
InnoDB是事务安全型的,MyISAM是非事务安全型的;
锁机制不同
MyISAM是表级锁,innoDB是行锁;
增删改查操作
MyISAM,如何执行大量的Select操作,MyISAM是最好的选择;
InnoDB,如果使用大量的Insert,Update操作,出于性能方面的考虑,
查询表的行数不同
MyISAM,当select count(*) from table,MyISAM只要简单的读出保存好的行数,注意的是,当count(*)语句包含where条件时,两种表的操作是一样的;
InnoDB,InnoDB中不保存具体的行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行。
外键支持
MyISAM不支持外键,InnoDB支持
MyISAM比InnoDB的查询快
InnoDB在做select的时候,要维护的东西比MyISAM引擎多很多;
数据块,InnoDB要缓存,MyISAM只缓存索引块,这中间还有换进换出的减少;
InnoDB的寻址要先映射到块,再到行,MyISAM记录的直接是文件的OPENSET,定位比INNODB要快。
InnoDB还要维护MVCC一致;虽然你的场景没有,但是他还是需要去检查维护;
MVCC:多版本并发控制
应用场景:
MyISAM适合:
- 做很多count的计算;
- 插入不频繁,查询非常平凡
- 没有事务
InnoDB适合:
- 可靠性要求比较高,或者要求事务
- 表更新和查询都相当频繁,并且行锁定的机会比较大的情况;
10. MySql的四种事务隔离级别,每种隔离级别解决了什么问题?
四种事务隔离级别从隔离程度上越来越高,但同时在并发性上也就越来越低。之所以有这么几种隔离级别,就是为了方便开发人员在开发过程中根据业务需要选择最合适的隔离级别。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 可能 | 可能 | 可能 |
不可重复读(read-committed) | 不可能 | 可能 | 可能 |
可重复读(repeatable-read) | 不可能 | 不可能 | 可能(MySQLInnoDB不可能) |
可序列化(serializable) | 不可能 | 不可能 | 不可能 |
-
读未提交(Read uncommitted)
最低的隔离级别,在这种事务隔离级别下,一个事务可以读到另一个事务未提交的数据;
原理:
事务在读数据的时候,并未对数据加锁。事务在修改数据的时候只对数据增加行级共享锁;
现象:
事务1读取某行记录时,事务2也能对这行记录进行读取、更新(因为事务一并未对数据增加任何锁)
当事务2对该记录进行更新时,事务1再次读取该记录,能读到事务2对该记录的修改版本(因为事务二只增加了共享读锁,事务一可以再增加共享读锁读取数据),即使该修改尚未被提交。
事务1更新某行记录时,事务2不能对这行记录做更新,直到事务1结束。(因为事务一对数据增加了共享读锁,事务二不能增加排他写锁进行数据的修改)
举例:
事务一 事务二 /* Query 1 */
SELECT age FROM users WHERE id = 1;
/* will read 20 */
/* Query 2 */
UPDATE users SET age = 21 WHERE id = 1;
/* No commit here */
/* Query 1 */
SELECT age FROM users WHERE id = 1;
/* will read 21 */
ROLLBACK;
/* lock-based DIRTY READ */
说明:事务一共查询了两次,在两次查询的过程中,事务二对数据进行了修改,并未提交(commit)。但是事务一的第二次查询查到了事务二的修改结果。在数据库的读现象浅析中我们介绍过,这种现象我们称之为脏读。
所以,未提交读会导致脏读
读未提交会导致脏读;
-
不可重复读(Read committed)
在一个事务修改过程中,若这个事务还没有提交,则其他事务不能读取该数据
原理:
事务对当前被读取的数据加行级共享锁(当读到时才加锁)**,**一旦读完该行,立即释放该行级共享锁;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加行级排他锁,直到事务结束才释放。
现象:
事务1在读取某行记录的整个过程中,事务2都可以对该行记录进行读取(因为事务一对该行记录增加行级共享锁的情况下,事务二同样可以对该数据增加共享锁来读数据。)。
事务1读取某行的一瞬间,事务2不能修改该行数据,但是,只要事务1读取完改行数据,事务2就可以对该行数据进行修改。(事务一在读取的一瞬间会对数据增加行级共享锁,任何其他事务都不能对该行数据增加排他锁。但是事务一只要读完该行数据,就会释放行级共享锁,一旦锁释放,事务二就可以对数据增加排他锁并修改数据)
事务2更新某行记录时,事务1不能对这行记录做读取或更新,直到事务2结束。(事务2在更新数据的时候,会对该行数据增加排他锁,直到事务结束才会释放锁,所以,在事务2没有提交之前,事务1都不能对数据增加共享锁进行数据的读取。
举例:
事务一 事务二 /* Query 1 */
SELECT * FROM users WHERE id = 1;
/* Query 2 */
UPDATE users SET age = 21 WHERE id = 1;
COMMIT;
/* in multiversion concurrency control, or lock-based READ COMMITTED */
/* Query 1 */
SELECT * FROM users WHERE id = 1;
COMMIT;
/*lock-based REPEATABLE READ */
说明:在读已提交隔离级别中,在事务二提交之前,事务一不能读取数据。只有在事务二提交之后,事务一才能读数据。
但是从上面的例子中我们也看到,事务一在一次事务中两次读取的结果并不一致,所以提交读不能解决不可重复读的读现象。
简而言之,提交读这种隔离级别保证了读到的任何数据都是提交的数据,避免了脏读(dirty reads)。但是不保证事务重新读的时候能读到相同的数据,因为在每次数据读完之后其他事务可以修改刚才读到的数据。
读已提交会解决脏读的现象;
-
可重复读(Repeatable reads)
由于读已提交隔离级别会产生不可重复读现象,所以,比读已提交更高一隔离级别就可以解决不可重复读问题,这种隔离级别就叫可重复读;
原理:
事务在读取某数据的瞬间(就是开始读取的瞬间),必须先对其加行级共享锁,直到事务结束才释放;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加行级排他锁,直到事务结束才释放。
现象:
事务1在读取某行记录的整个过程中,事务2都可以对该行记录进行读取(因为事务一对该行记录增加行级共享锁的情况下,事务二同样可以对该数据增加共享锁来读数据。)。
事务1在读取某行记录的整个过程中,事务2都不能修改该行数据(事务1在读取的整个过程会对数据增加共享锁,直到事务提交才会释放锁,所以整个过程中,任何其他事务都不能对该行数据增加排他锁。所以,可重复读能够解决不可重复读的读现象)
事务1更新某行记录时,事务2不能对这行记录做读取、更新,直到事务1结束。(事务1在更新数据的时候,会对该行数据增加排他锁,知道事务结束才会释放锁,所以,在事务2没有提交之前,事务一都能不对数据增加共享锁进行数据的读取。所以,提交读可以解决脏读的现象)
举例:
事务一 事务二 /* Query 1 */
SELECT * FROM users WHERE id = 1;
COMMIT;
/* Query 2 */
UPDATE users SET age = 21 WHERE id = 1;
COMMIT;
/* in multiversion concurrency control, or lock-based READ COMMITTED */
说明:只有在事务一提交之后,事务二才能更改该行数据。所以,只要在事务一从开始到结束的这段时间内,无论他读取该行数据多少次,结果都是一样的。
从上面的例子中我们可以得到结论:可重复读隔离级别可以解决不可重复读的读现象。但是可重复读这种隔离级别中,还有另外一种读现象他解决不了,那就是幻读。
可重复读会解决不可重复读的现象
-
可序列化:
可序列化(Serializable)是最高的隔离级别,前面提到的所有的隔离级别都无法解决的幻读,在可序列化的隔离级别中可以解决。
我们说过,产生幻读的原因是事务一在进行范围查询的时候没有增加范围锁(range-locks:给SELECT 的查询中使用一个“WHERE”子句描述范围加锁),所以导致幻读。
原理:
事务在读取数据时,必须先对其加表级共享锁 ,直到事务结束才释放;
事务在更新数据时,必须先对其加表级排他锁 ,直到事务结束才释放。
现象:
事务1正在读取A表中的记录时,则事务2也能读取A表,但不能对A表做更新、新增、删除,直到事务1结束。(因为事务一对表增加了表级共享锁,其他事务只能增加共享锁读取数据,不能进行其他任何操作)
事务1正在更新A表中的记录时,则事务2不能读取A表的任意记录,更不可能对A表做更新、新增、删除,直到事务1结束。(事务一对表增加了表级排他锁,其他事务不能对表增加共享锁或排他锁,也就无法进行任何操作)
举例:
事务一 事务二 /* Query 1 */
SELECT * FROM users WHERE age BETWEEN 10 AND 30;
/* Query 2 */
INSERT INTO users VALUES ( 3, 'Bob', 27 );
COMMIT;
/* Query 1 */
SELECT * FROM users WHERE age BETWEEN 10 AND 30;
说明:
1.事务一的第一次查询条件是
age BETWEEN 10 AND 30;
如果这是有十条记录符合条件。这时,他会给符合条件的这十条记录增加行级共享锁。任何其他事务无法更改这十条记录。 2.事务二执行一条sql语句,语句的内容是向表中插入一条数据。因为此时没有任何事务对表增加表级锁,所以,该操作可以顺利执行。
3.事务一再次执行
SELECT * FROM users WHERE age BETWEEN 10 AND 30;
时,结果返回的记录变成了十一条,比刚刚增加了一条,增加的这条正是事务二刚刚插入的那条。问题:
虽然可序列化解决了脏读、不可重复读、幻读等读现象。但是序列化事务会产生以下效果:
1.无法读取其它事务已修改但未提交的记录。
2.在当前事务完成之前,其它事务不能修改目前事务已读取的记录。
3.在当前事务完成之前,其它事务所插入的新记录,其索引键值不能在当前事务的任何语句所读取的索引键范围中。
可序列化会解决幻读的现象
11. Mysql的可重复读隔离级别是如何解决幻读问题的?
- 快照读:通过MVCC(多版本控制)来避免幻读;
- 当前读:通过gap锁来避免幻读;
12. MySql的索引类别?聚集索引和非聚集索引是什么?有什么区别?什么场景下使用?
索引类别:
- 普通索引
- 唯一索引
- 主键索引
- 组合索引
- 全文索引
聚簇索引和非聚簇索引
数据库的InnoDB引擎的数据存储本来就是按照B+Tree树的形式进行存储;
聚簇索引:B+Tree树的叶子节点直接存储的就是数据;
非聚簇索引:B+Tree树叶子节点存储的是辅助索引,需要通过辅助索引来进行二次查找来定位到数据;
聚簇索引主键的插入速度要比非聚簇索引的插入速度慢很多;
相比之下,聚簇索引适合排序,非聚簇索引不适合在排序的场合,因为聚簇索引本来就是按照物理顺序存放的,排序很快,非聚簇索引没有按照顺序存放,需要额外消耗资源来排序;
当你取出一定范围内的数据时,用聚簇索引也比用非聚簇索引要好;
覆盖索引
若查询使用的索引包含了需要查询的字段,那么这就是覆盖索引;
13. 数据库读写分离
什么是读写分离:
基本的原理就是让分主从数据库,主数据负责数据的增删改操作,从数据库负责数据的查询操作;
为什么要使用读写分离:
以Oracle为例:
-
Oracle读10000条数据需要4秒钟;
-
Oracle写入10000条数据需要3分钟;
解决的问题就是:数据库的写入操作影响数据库执行效率问题;
什么时候要使用读写分离:
数据库不一定要读写分离,但是如果程序使用数据库较多,而更新少,查询多的情况下会考虑使用,利用数据库的主从同步,会减少数据库的压力。
主从复制与读写分离:
在实际的生产环境中,对数据库的读和写都在同一个数据库服务器中,是不能满足实际需求的。无论是在安全性、高可用性还是高并发等各个方面都是完全不能满足实际需求的。因此,通过主从复制的方式来同步数据,再通过读写分离来提升数据库的并发负载能力。mysql主从复制是对数据库中的数据、语句做备份。
- MySql支持的复制类型:
- 基于语句的复制,在服务器上执行sql语句,在从服务器上执行同样的语句,MySql默认采用基于语句的复制,执行效率高。
- 基于行的复制,把改变的内容复制过去,而不是把命令在从服务器上执行一遍。
- 混合类型的复制,默认采用基于语句的复制,一旦发现基于语句无法复制时,就会采用基于行的复制
常用的MySql读写分离原理:
-
基于程序代码内部实现;
在代码中根据select,insert进行路由分类,这类方法也是目前生产环境中应用最广泛的,优点是性能好,应为是在程序内部实现,所以不需要额外的硬件开支,缺点是需要开发人员来实现,运维人员无从下手。
-
基于中间代理层实现;
代理一般基于应用服务器和数据库服务器之间,代理数据库服务器接收到请求后根据判断后转发到后端数据库。
14. jdk1.8对ConcurrentHashMap加了哪些新特性
HashTable虽然说是线程安全的,但是效率低下,但是ConcurrentHashMap线程安全且效率高,这是因为他引入了分段锁的机制。
线程安全且效率高的原理:
ConcurrentHashMap中默认是把segments初始化为长度为16的数组。
假设Thread1和Thread2两个线程同时操作一个Segment,Thread1和Thread2先后进入Segment.put方法时,Thread1会首先获取到锁,可以进入,而Thread2则会阻塞在锁上;
当Thread3根据hashCode判断出位置,和Thread1和Thread2操作的不是同一个Segment时,则会继续进行put操作。
ConcurrentHashMap通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。
ConcurrentHashMap时使用了CAS + Synchronized并且它保留了红黑树的结构,所以效率会比HashTable要高
15. 说一下JVM中你了解哪些知识
JVM使根据GC Root判读是否需要回收,每次引用都可以作为它的GC Root
15.1 垃圾回收算法:
-
标记-清除法:
jvm会扫描对象的实例,通过搜索算法,将活跃的对象进行标记,jvm再次扫描所有对象,将未标记的对象进行清除。
缺点:会导致大量的内存碎片;
-
复制:
jvm会标记被引用的对象,之后会申请新的内存空间,将标记的对象拷贝到新的内存空间,然后再清除原有的内存空间,这样就解决了产生大量碎片的问题。
缺点:若标记的对象很多,那么需要申请的内存空间就会很大,在内存不足的场景下,会对jvm运行造成很大的压力。
-
标记-整理:
其实就是在标记清除算法上的优化,执行标记清除过程之后,再一次对内存进行整理,将所有的存活对象向内存区域的一端移动。
-
分代回收算法:
年轻代:
分为三个区:eden,survivor1,survivor2,内存占比默认8:1:1可以使用参数进行设置,survivor区的年龄大于15就会进入老年代,可使用参数进行设置,创建的对象不一定直接进入年轻代,若是很大的对象,他会直接进入老年代中。
复制算法,因为年轻代存活的对象比较多,但是存活的对象比较少,所以采用复制法比较合适。
老年代:标记整理法,因为老年代的存活对象比较多,但是需要清除的对象比较少,所以标记整理法比较合适。
15.2 垃圾收集器
主要讲解CMS(Concurrent Mark Sweep),G1
15.2.1 CMS
Concurrent:多线程
Mark:标记
Sweep:清除
工作机制:
第一步:初始标记GC Root直接相关对象(单线程),会产生Stop-the-word(jvm挂起)现象:
第二步:标记GC Root间接相关对象(多线程);
第三步:重新标记新产生的可能GC垃圾回收的对象(多线程);
第四步:清除垃圾(并发);
缺点:由于最后一步是并发执行的,所以可能产生一边清除一边产生垃圾的问题;
15.2.2 G1
并非按照年轻代和老年代来分,分为很多个Region然后Region又分为Eden Space和Survivor Space和Old Space
16. Linux如何查看当前进程内存状况及使用情况
- ps aux|grep process_name
- pmap pid
17. JVM的内存结构
17.1 线程共享的
- 方法区(java虚拟机的模型规范)
- 元空间(分布在计算机内存,脱离java虚拟机内存独立存在。类文件常量存放位置)
- 永久代(jdk1.7,1.8之后移除)
- 堆(字符串常量存放位置)
17.2 线程独占的
- 程序计数器
- 本地方法栈
- 虚拟机栈
18. 类加载
类加载实际上就是将类加载到堆和方法区中;
类加载器的种类:
java类加载器的双亲委派模型:
启动类记载器
用户无法直接使用,在<java_home>/lib中
扩展类记载器
用户可以直接使用,在<java_home>/lib/ext中
应用程序类加载器
用户可以直接使用,若用户没有自定义类加载器,则会默认使用该记载器
用户自定义类加载器
用户自己定义的类加载器
19. ThreadLocal和Synchronized
ThreadLocal:父子线程之间不可以继承,若有线程继承的需求,则需要使用InHeriTableThreadLocal
Synchronized:
锁升级(jdk1.6之后):
- jdk1.6之前:没有锁升级的过程,要么就是全部给要么就是全部不给
- jdk1.6之后(分为四个等级):
- 无锁
- 偏向锁:一个请求去请求资源,若没其他请求去请求资源,他会一直占有资源,不释放锁,避免了瞬时态转换为用户态的问题,当两个线程争抢资源,就会升级为轻量级锁;
- 轻量级锁:有其他请求来争抢资源,CAS来判断是否能得到资源,不会就会等待(自旋),然后时间过长就会升级为重量级锁;
- 重量级锁
- 两者都是为解决多线程中的相同变量的访问冲突问题;
- ThreadLocal是每个线程一个独立的Map(Key是线程的引用)实现线程隔离的效果,是一种空间换时间的做法,而Synchronized是牺牲时间来换空间的做法;
20. java的动态代理
jdk动态代理和CGLIB动态代理;
jdk是java自带的代理模式;
CGLIB是第三方的代理模式,需要第三方库的支持
21. java单例模式:
单例模式:
懒汉模式:指的是调用的时候创建对象。
饿汉模式:指的时把创建对象设成静态的,在使用之前就创建对象;
22. JWT(JSON WEB TOKEN)
分为三个部分:
Header
用来承载算法,使用Base64Url进行编码;
alg算法默认是SHA256、HMAC简写成HS256
结构:
{
“typ” : “JWT”,
“alg” : “HS256”
}
playload
用来承载要传递的数据,使用Base64Url进行编码;
结构:
{
“sub” : “123456789”,
“name” : “zhangsan”,
“admin” : true
}
signature
存放签名;
实际是将header和playload中的base64url编码的数据进行拼接,中间加了一个".",然后在使用header中的alg定义的算法处理
结构:
HMACSHA256 (
base64UrlEncode(header) + “.” +
base64UrlEncode(playload),
secret
)
JWT的优缺点:
- 优点:
- 可扩展性好,session需要多机共享,通常存在数据库或redis上,但是JWT不需要;
- 无状态,JWT不在服务端存储任何状态;
- 缺点:
- 安全性,由于JWT的payload是Base64编码的,并没有进行加密,而session的信息是存在服务端的,相对来说更安全;
- 性能,由于Http的每次请求都要将jwt放到请求的head里,经过编码后jwt将会变得非常长,甚至有的时候jwt可能会比body存储的数据还要大,所以,使用jwt的http请求开销要比session要大的多;
- 一次性,无状态是jwt的特点,但是也导致了这个情况的产生。jwt是一次性的,若想要修改JWT里边的内容就必须要再发送一次jwt
- 无法废弃,一旦签发一个jwt,那么将会在到期时间之前就会一直有效,当签发了一个新的jwt时,旧的依然有效就会出现问题,为了解决这个问题,我们就要在服务端进行独立的部署,一旦签发了新的jwt,那么旧的就会加入黑名单(比如redis中),避免再次使用;
- 续签:如果在处理会话的过程中,若使用session,session的默认过期时间是30分钟,若在30分钟之内,每次处理一个会话,那么过期时间就会往后推30分钟,但是jwt确是每次会话都会发送一个新的jwt,这样会严重地影响系统的性能(还有一种方式是在redis中来进行处理每次会话重置过期时间,但是引入了redis的话就会将无状态变为有状态,这样就违背了jwt设计的初衷)。
总结:
适合使用jwt的场景:
- 有效期短。
- 只希望被使用一次。
例如:激活邮件。
不适合使用jwt的场景:
例如:单点登录/会话管理;若在服务器端来部署额外的逻辑来存储jwt的状态,那还不如直接试用jsession,因为session有开箱即用的特性,要比jwt方便得多;
23. Redis
Redis不支持事务,失败就直接失败;
Mysql支持事务,失败可以进行回滚操作;
Redis持久化方式:RDB和AOF(类似于日志);
24. Mysql执行流程
25. Map的有序存储
HashMap是没有顺序的,若想使用有序的map那么就要使用到TreeMap和LinkedHashMap,
LinkedHashMap继承了HashMap但是若是不将Access-order设置为true,那么它将和HashMap没有什么区别,他的有序是因为他引入了双向链表来存储数据的顺序。
TreeMap实现了SortMap接口,有比HashMap更强大的功能,TreeMap的性能要低于HashMap。是根据元素的固有顺序进行排序,他的顺寻主要取决于Comparator和Comparable;
这篇关于2020年五月份面试题总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!