一、Java工程师进阶①

面试常见问题

一、Object的Hash该怎么设计
Hash返回的是一个整数,它代表的是当前对象的Hash值,如果两个对象相等,那么他们的Hash值也一定相等,如果一个类自定义了equles()方法,并且这个类的实例有可能会被添加进集合中的时候,一定要确保hash()方法被重新定义。

二、哈希碰撞
当两个不同的对象计算出相同的散列值的时候,就称之为发生了哈希碰撞,发生碰撞时,哈希表会从碰撞的位置开始向后寻找,把新的元素放在第一个可供放置的位置上,随着哈希表的密集,发生碰撞的几率也会增大,导致查找合适位置的时间越来越长,这也是为什么我们希望哈希函数是均匀分布的结果。

三、数据库的三个范式
1NF:强调原子性
2NF:在1NF的基础上,存在主键,没有包含在主键里的列必须完全依赖于主键,不能只依赖一部分
3NF:在2NF的基础上,非主键列必须直接依赖于主键,不能存在传递依赖

四、HashMap为什么是线程不安全的
HashMap 在put的时候,插入的元素如果超过了容量的话就会发生扩弄操作,这个操作会将原数组中的数据重新hash到新得数组中去,在多线程情况下,同时可能会有多个线程在进行put操作,这时,如果他们put的hashcode值相等的情况下,可能会出现同一个数组下用链表表示,造成闭环,导致在get的时候会出现死循环。

五、TCP和UDP
TCP 是面向连接的,UDP 是面向无连接的
UDP程序结构较简单
TCP 是面向字节流的,UDP 是基于数据报的
TCP 保证数据正确性,UDP 可能丢包
TCP 保证数据顺序,UDP 不保证

TCP的三次握手和四次挥手
1、三次握手
首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源。Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连接就建立了。
1)第一次握手:A的TCP客户进程也是首先创建传输控制块TCB,然后向B发出连接请求报文段,(首部的同步位SYN=1,初始序号seq=x),(SYN=1的报文段不能携带数据)但要消耗掉一个序号,此时TCP客户进程进入SYN-SENT(同步已发送)状态。
2)第二次握手:B收到连接请求报文段后,如同意建立连接,则向A发送确认,在确认报文段中(SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y),测试TCP服务器进程进入SYN-RCVD(同步收到)状态;
3)第三次握手:TCP客户进程收到B的确认后,要向B给出确认报文段(ACK=1,确认号ack=y+1,序号seq=x+1)(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。TCP连接已经建立,A进入ESTABLISHED(已建立连接)。
当B收到A的确认后,也进入ESTABLISHED状态。

2、四次挥手
1)A的应用进程先向其TCP发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN-WAIT-1(终止等待1)状态,等待B的确认。
2)B收到连接释放报文段后即发出确认报文段,(ACK=1,确认号ack=u+1,序号seq=v),B进入CLOSE-WAIT(关闭等待)状态,此时的TCP处于半关闭状态,A到B的连接释放。
3)A收到B的确认后,进入FIN-WAIT-2(终止等待2)状态,等待B发出的连接释放报文段。
4)B没有要向A发出的数据,B发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),B进入LAST-ACK(最后确认)状态,等待A的确认。
5)A收到B的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),A进入TIME-WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,A才进入CLOSED状态。

常见问题:
为什么A在TIME-WAIT状态必须等待2MSL的时间?
答:  两个理由:
1)保证A发送的最后一个ACK报文段能够到达B。
2)防止“已失效的连接请求报文段”出现在本连接中。

为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。

六、线程
sleep和wait的区别
1、sleep来自Thread类,wait来自Object,调用sleep方法时,线程不会释放对象锁,调用wait方法时,线程会释放对象锁,
2、sleep不会让出系统资源,wait会让其他线程占据CPU
3、sleep的唤醒是通过设置一个毫秒数,wait是使用notify或者notifyAll来唤醒

notify和notifyAll的区别
如果线程调用了对象的wait方法,那么线程便会处在该对象的等待池中,等待池的对象不会竞争该对象的锁,当有线程调用了notify(唤醒一个)或者notifyAll(唤醒所有),那被唤醒的线程就会进入该对象的的锁池,锁池中的对象会主动竞争对象锁,再次调用wait方法时,他才会重新进入到等待池中。

七、JVM
程序计数器
内存空间小,线程私有。字节码解释器工作是就是通过改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成

Java 虚拟机栈
线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。

本地方法栈
区别于 Java 虚拟机栈的是,Java 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。也会有 StackOverflowError 和 OutOfMemoryError 异常。

Java 堆
对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组。内部会划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)。可以位于物理上不连续的空间,但是逻辑上要连续。

方法区
属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

JVM垃圾回收机制
程序计数器,虚拟机栈,本地方法区随线程而生,随线程而灭,Java中的堆和方法区是动态的回收方式

引用计数法
引用计数法描述的算法为:给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已“死”。
但是无法解决循环引用的问题

可达性分析算法
通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为“引用链”,当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可用。

可作为GC Root的对象
虚拟机栈(栈帧中的本地变量表)中引用的对象。
方法区中静态属性引用的对象
方法区中常量引用的对象
本地方法栈中(Native方法)引用的对象

回收方法区
方法区(永久代)的垃圾回收主要收集两部分内容:废弃常量和无用类。
回收废弃常量和回收Java堆中的对象十分类似。以常量池中字面量(直接量)的回收为例,假如一个字符串"abc"已经进入了常量池中,但是当前系统没有任何一个String对象引用常量池中的"abc"常量,也没有其他地方引用这个字面量,如果此时发生GC并且有必要的话,这个"abc"常量会被系统清理出常量池。常量池中的其他类(接口)、方法、字段的符号引用也与此类似。

判定一个类是否是"无用类"则相对复杂很多。类需要同时满足下面三个条件才会被算是"无用的类"
1.该类的所有实例都已经被回收(即在Java堆中不存在任何该类的实例)
2.加载该类的ClassLoader已被回收
3.该类对应的Class对象没有任何其他地方被引用,无法在任何地方通过反射访问该类的方法

标记-清除算法
“标记-清除”算法是最基础的收集算法。算法分为标记和清除两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

标记-清除”算法的不足主要有两个:
效率问题:标记和清除这两个过程的效率都不高
空间问题:标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集。

复制算法(新生代回收算法)
“复制”算法是为了解决“标记-清除”的效率问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中一块。当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另一块上面,然后再把已经使用过的内存区域一次清理掉。
好处:是每次都是对整个半区进行内存回收,内存分配时也就不需要考虑内存碎片等的复杂情况,只需要移动堆顶指针,按顺序分配即可。此算法实现简单,运行高效。

标记整理算法(老年代回收算法)
复制收集算法在对象存活率较高时会进行比较多的复制操作,效率会变低。因此在老年代一般不能使用复制算法。
针对老年代的特点,提出了一种称之为“标记-整理算法”。标记过程仍与“标记-清除”过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象向一端移动,然后直接清理掉端边界以外的内存。

面试题: 请问了解Minor GC和Full GC么,这两种GC有什么不一样吗?
Minor GC又称为新生代GC : 指的是发生在新生代的垃圾收集。因为Java对象大多都具备朝生夕灭的特性,因此Minor GC(采用复制算法)非常频繁,一般回收速度也比较快。
Full GC 又称为老年代GC或者Major GC : 指发生在老年代的垃圾收集。出现了Major GC,经常会伴随至少一次的Minor GC(并非绝对,在Parallel Scavenge收集器中就有直接进行Full GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。

JVM内存泄露和内存溢出
内存泄漏:系统分配的内存没有被回收
原因:在堆中存在真正的引用对象,方法执行的时候可能将栈内存清空,但堆内存不应清空,导致堆内存的无用对象没办法回收
内存溢出:分配的空间超过系统内存
原因:
1、使用了大量的jar或者class,使虚拟机内存不够
2、创建的对象太多,在垃圾回收算法执行之前堆就满了
3、多线程情况下每个线程耗时太多

八、Lock和Synchronized的区别
1、lock是一个接口,Synchronized 是一个关键字,代码出现异常时Synchronized 会自动解锁,而Lock不会,必须要手动释放锁。
2、Synchronized 不会发生死锁,Lock如果没有手动释放锁就容易发生死锁
3、Lock可以让等待锁的线程响应中断,Synchronized 会让线程一直等待下去
4、Lock可以提高多线程下的读操作的效率

重入锁
自己可以获取自己内部的锁,可以防止死锁,Synchronized 是可重入锁,他修饰了一个子类和父类共有的方法,在子类调用父类的方法时,实际上是调用了父类的方法,实例方法的调用是在JVM运行时动态绑定的。

产生死锁的四个条件
1、互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。
2、占有且等待:一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。
3、不可抢占:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。
4、循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。

线程池的种类:
可缓存线程池:如果线程池的长度超过处理的需要,则会灵活的回收空线程,若无可回收,则创建线程
单线程化线程池:用唯一的工作线程来执行任务,保证所有的任务按照指定顺序执行
定长线程池:支持定时以及周期性的任务
定量线程池:控制线程的最大并发数,超出的话,线程会在队列中等待

类加载的过程
加载:从.class文件中加载
验证:确保加载的文件的信息不会危害到虚拟机安全
准备:分配内存,设置要初始化的值
解析:将常量池中的符号引用变成直接引用
初始化
注意以下情况不会被初始化
1、子类调用父类的静态字段
2、定义对象数组
3、常量池中的常量在编译期间
4、通过类名获取.class对象

Java中的BIO/NIO/AIO
1、同步阻塞的BIO:用户发送请求,一直等待数据是否准备好,没有准备好的话一直等待,准备好后发给用户
2、同步非阻塞的NIO:用户发送请求,无论是否准备好,都返回一个结果,直到请求成功。
3、异步非阻塞的AIO:用户发送请求,无论是否准备好,都返回一个结果,此时有一个监听器,监听这个,直到数据都准备好了,监听器让用户发送请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值