欢迎大家来到IT世界,在知识的湖畔探索吧!
一面
在第一次面试中主要针对于之前所做的项目询问了一些细节。Java方面的问题则提问了Servelt的生命周期,线程的状态,加密算法(非对称,对称,MD5)以及数据库事务ACID四大特性。
①面试官问:Servelt的生命周期
1.创建servlet实例
2.当servlet实例化后,将调用这个对象的init()方法进行初始化
3.再调用对象的service()方法来处理请求,并返回处理结果,在调用service之前,需保证init初始化已被成功执行
4.当需要释放servlet的时候,调用对象的destroy()方法来结束,并释放资源
②面试官问:线程的状态
Java中线程的状态分为6种:
- 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
- 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统地称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。 - 阻塞(BLOCKED):表示线程阻塞于锁。
- 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
- 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。终止(TERMINATED):表示该线程已经执行完毕。
③加密算法(非对称,对称,MD5)
MD5加密
MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。这套算法的程序在 RFC 1321 中被加以规范。
将数据(如一段文字)运算变为另一固定长度值,是散列算法的基础原理。
1996年后被证实存在弱点,可以被加以激活成功教程,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。2004年,证实MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL 公开密钥认证或是数字签名等用途。
2009年,中国科学院的谢涛和冯登国仅用了220.96的碰撞算法复杂度,激活成功教程了MD5的碰撞抵抗,该攻击在普通计算机上运行只需要数秒钟。
MD5加密的特点:
1. 不可逆运算
2. 对不同的数据加密的结果是定长的32位字符(不管文件多大都一样)
3. 对相同的数据加密,得到的结果是一样的(也就是复制)。
4. 抗修改性 : 信息“指纹”,对原数据进行任何改动,哪怕只修改一个字节,所得到的 MD5 值都有很大区别.
5. 弱抗碰撞 : 已知原数据和其 MD5 值,想找到一个具有相同 MD5 值的数据(即伪造数据)是非常困难的.
6. 强抗碰撞: 想找到两个不同数据,使他们具有相同的 MD5 值,是非常困难的
MD5 应用:
一致性验证:MD5将整个文件当做一个大文本信息,通过不可逆的字符串变换算法,产生一个唯一的MD5信息摘要,就像每个人都有自己独一无二的指纹,MD5对任何文件产生一个独一无二的数字指纹。
对称加密
网络的数据传输从发送方发出到接收方接收到,要经过数个节点才能到达目的地,在这个过程中难免会被别有用心的人监听(现在常用的网络数据监听软件就有charles,具体可以查看相关使用教程,通过这个软件可以监听到某个页面用到了哪些接口,发送以及返回的参数分别是什么)。
所以在传输敏感数据的过程中,就要对数据进行加密。现行的加密过程中,一般加密算法是公开的,密钥是自己持有,发送方有密钥对数据进行加密传输,在传输的过程中经过加密的数据即使被第三方窃取到也因为没有密钥不能解密。而接收方同样持有密钥通过算法的逆运算把密文解析出对应的明文来。
过程如下:
上述算法即为对称加密,特点是加密和解密都是用同一个密钥。这种算法的前提条件是发送方和接收方用一个密钥,也就是说在数据传输之前,接收方要知道发送方用于发送加密数据所用到的密钥。但是现实条件是一般不会把密钥手把手地交给对方,所以下面就要用到非对称加密算法。
非对称加密算法
非对称加密算法中信息的发送方和接收方都分别有两个密钥,其中分别为私钥和公钥,私钥为数据的发送方持有,公钥可以公开。其中涉及到两种模式,它们分别为加密模式和认证模式。
加密模式:
发送方用公钥给数据进行加密,然后把加密后的数据发送到接收方,然后接收方用对应的私钥解密,因为只有接收方的私钥才能解析数据,所以即使被第三方窃取到数据也没有关系。这个模式叫做加密模式。
在这个过程中如何保证数据的完整性,保证数据是发送方发送的数据,而不是被第三方篡改后的数据。这时就要用到签名,在发送方加密明文之前,给明文取md5值,得到其信息的摘要(注:不能通过信息摘要反推明文)。然后用公钥分别给明文和明文的摘要加密发送到数据的接收方,数据的接收方接收到数据之后,用私钥对密文和摘要进行解密,然后对解密得到的明文取md5摘要,比对解密后的明文摘要和发送过来的摘要是否一致;一致就证明数据是原始的数据没有遭到篡改。
这个加密的过程中保证了数据的安全性(即只有接收方才可以解密)和防篡改性(签名认证),这就保证了上面说的数据传输要求中的第一点和第三点。下面是图解过程:
但是因为公钥是公开的,所以在加密模式中我们是不知道到底是谁发送数据给我们的,因此下面就要提到认证模式。
认证模式:
在认证模式中,发送方用私钥加密数据,给接收方发送数据,接收方用公钥解密,因为私钥是唯一的,所以只要数据解析成功就可以知道数据发送方是谁。
这就符合我们在数据的传输要求中的第二点了。下面是图解过程:
结合加密模式和认证模式就可以实现数据传输安全的三大要点了。
下面我们来解释一下这种高级模式,以发送方和接收方两个部分来解释:
- 将消息进行散列运算,得到消息摘要。
- 使用自己的私钥对消息摘要加密(认证模式:确保了接收方能够确认自己)。
- 使用接收方的公钥对消息进行加密(加密模式:确保了消息只能由期望的接收方解密)。
- 发送消息和消息摘要。
接下来我们看一下接收方所执行的步骤:
1. 使用发送方的公钥对消息摘要进行解密(确认了消息是由谁发送的)。
2. 使用自己的私钥对消息进行解密(安全地获得了实际应获得的信息)。
3. 将消息进行散列运算,获得消息摘要。
4. 将上一步获得的消息摘要 和 第一步解密的消息摘要进行对比(确认了消息是否被篡改)。
以看到,通过上面这种方式,使用了接收方、发送方全部的四个密钥,再配合使用消息摘要,使得前面提出的安全传递的所有三个条件全都满足了。那么是不是这种方法就是最好的呢?不是的,因为我们已经说过了,非对称加密是一种很耗时的操作,所以这个方案是很低效的。实际上,我们可以通过非对称加密来解决对称加密中的密钥传递问题,如果你已经忘记了可以翻到前面再看一看,也就是说,我们可以使用这里的高级实现方式来进行对称加密中密钥的传递,对于之后实际的数据传递,采用对称加密方式来完成,因为此时已经是安全的了。
④数据库事务ACID四大特性
原子性(Atomicity):化学中的原子指不可再分的基本微粒,数据库中原子性强调事务是一个不可分割的整体,事务开始后所有操作要么全部成功,要么全部失败,不可能停滞在中间某个环节。如果事务执行过程中出错就会回滚到事务开始前的状态,所有的操作就像没有发生一样不会对数据库有任何影响。
一致性(Consistency):事务必须使数据库从一个一致性状态变换到另一个一致性状态,即一个事务执行之前和执行之后都必须处于一致性状态。拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还是5000,这就是事务的一致性。
隔离性(Isolation):当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离,比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转入钱。
持久性(Durability):一个事务一旦被提交,则对数据库的所有更新将被保存到数据库中,不能回滚。
二面(电话面)
在第二次面试中,面试官问到了Java的内存模型(原子性,有序性,可见性),Java中集合的层次,JVM的垃圾回收机制,HashMap、Hashtable、ConcurrentHashMap的区别,同步器实现机制。还问了我使用过哪些ORM框架,有一次问到了数据库事务的四大特性,还问了注解处理器,以及原子类底层机制(cas, Unsafe)以及快排实现方式。
①Java的内存模型(原子性,有序性,可见性)
1、原子性(Atomicity)
由Java内存模型来直接保证的原子性变量包括read、load、assign、use、store和write,我们大致可以认为基本数据类型的访问读写是具备原子性的。
如果应用场景需要一个更大方位的原子性保证,Java内存模型还提供了lock和unlock操作来满足这种需求,尽管虚拟机未把lock和unlock操作直接开放给用户使用,但是却提供了更高层次的字节码指令monitorenter和monitorexit来隐式的使用这两个操作,这两个字节码指令反应到Java代码中就是同步块–synchronized关键字,因此在synchronized块之间的操作也具备原子性。
2、可见性(Visibility)
可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。volatile变量可以做到这一点。
Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现可见性的,无论是普通变量还是volatile变量都是如此,普通变量与volatile变量的区别是,volatile的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。
因此,可以说volatile保证了多线程操作时变量的可见性,而普通变量则不能保证这一点。除了volatile之外,Java还有两个关键字能实现可见性,即synchronized和final。
同步块的可见性是由“对一个变量执行unlock操作前,必须先把此变量同步回主内存”这条规则获得的,而final关键字的可见性是指:被final修饰的字段在构造器中一旦初始化完成,并且构造器没有把”this”的引用传递出去,那么在其他线程中就能看见final字段的值。
3、有序性(Ordering)
Java程序中天然的有序性可以总结为一句话:如果在本线程内观察,所有的操作都是有序的;如果在一个线程中观察另外一个线程,所有的线程操作都是无序的。前半句是指“线程内表现为串行的语义”,后半句是指“指令重排序”现象和“工作内存与主内存同步延迟”现象。
Java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性,volatile关键字本身就包含了禁止指令重排序的语义,而synchronized则是由“一个变量在同一个时刻只允许一条线程对其进行lock操作”这条规则获得的,这条规则决定了持有同一个锁的两个同步块只能串行的进入。
②Java集合的层次
③JVM的垃圾回收机制
垃圾回收(Garbage Collection)是Java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制。
④HashMap、Hashtable、ConcurrentHashMap的区别
HashTable
- 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
- 初始size为11,扩容:newsize = olesize*2+1
- 计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length
HashMap
- 底层数组+链表实现,可以存储null键和null值,线程不安全
- 初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
- 扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
- 插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
- 当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
- 计算index方法:index = hash & (tab.length – 1)
ConcurrentHashMap
- 底层采用分段的数组+链表实现,线程安全
- 通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
- Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
- 有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
- 扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容
⑤同步器实现机制
队列同步器 AQS(下文简称为同步器)主要是依赖于内部的一个 FIFO(first-in-first-out)双向队列来对同步状态进行管理的,当线程获取同步状态失败时,同步器会将当前线程和当前等待状态等信息封装成一个内部定义的节点 Node,然后将其加入队列,同时阻塞当前线程;当同步状态释放时,会将同步队列中首节点唤醒,让其再次尝试去获取同步状态。同步队列的基本结构如下:
三面(视频面)
ES的检索机制(query-then-fetch)
ES使用了倒排索引(inverted index),该结构对于全文检索非常快。
倒排索引包括一个在任意文档中出现的唯一性的词语列表,对于每个词语,都有一个它出现过的文档列表。
如下图所示:
Doc_1:
The quick brown fox jumped over the lazy dog
欢迎大家来到IT世界,在知识的湖畔探索吧!
Doc_2:
欢迎大家来到IT世界,在知识的湖畔探索吧!Quick brown foxed leap over lazy dogs in summer
②数据库事务特性以及隔离级别
Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read);
Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理期间可能会有新的commit,所以同一select可能返回不同结果;
Repeatable Read(可重读)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。
简单地说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。
InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题
Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/48736.html