Java每日30面试题---2020年9月22日

  1. HashMap 与 ConcurrentHashMap有什么区别

    HashMap和ConcurrentHashMap 最大的区别就是 ConcurrentHashMap是一个线程安全的map 而hashmap不是线程安全的。

    而且concurrentHashMap是一个读写分离的模式,每次扩容的时候都让线程去帮忙扩容,而hashmap 还是正常库容,hashmap的get是从table中拿的。

  2. HashMap 插入元素的过程

    当触发一个put(key,value)方法的时候,他会调用一个putVal 方法 ,然后最开始获取到hashcode 如果key是null 那么直接获取0 而不计算。然后根据路由算法 hash & length -1 得到一个索引值,然后根据索引值查找头结点有无数据,如果没有数据就直接插在头结点,如果有数据就一直遍历 看是不是链表,如果是链表就插入到末尾,在其中都会判断是否有key存在,如果存在就用newValue 替换oldValue,如果不是链表那就走红黑树的插入逻辑。

  3. interface 是什么?用 interface 有什么好处

    interface 是jvm的关键字,标识某个类是一个接口

    接口实现了对修改封闭,对扩展开发的原则。当你要扩展功能的时候,不用修改现有的设计的类,直接实现某个接口的类就可以了。

  4. Java 有内存泄露吗

    有,比如ThreadLocal中维护的ThreadLocalMap 的key是一个实现了虚引用的对象,而value是一个强引用对象。

    如果发生了一次gc 那么虚引用对象被回收了 那么map里面就有了一个key为null的entry。都知道threadLocalMap是会随着Thread类的消亡而消亡的,那么这么null的entry 也会跟着Thread消亡而消亡,此时就发生内存泄漏

  5. ArrayList与 LinkedList 有什么区别

    ArrayList 底层是数组实现的,需要扩容 每次库容1.5倍 提供随机访问

    LinkedList 底层是链表实现的,不需要扩容 添加删除的效率比ArrayList快

  6. volatile 关键字有什么作用

    volatile关键字修饰的变量,保证了变量的可见性,禁止指令重排,有序性。

  7. synchronized 和 reentrantlock` 的区别

    synchronized 是JVM提供的关键字,不可中断 只提供非公平锁,不需要手动释放锁 不可知道是否获取到锁 一直阻塞

    reentranlock 是API层面的锁,可中断 提供了非公平和公平锁的两种实现, 需要手动释放锁 可以知道是否获取到锁, 锁超时

  8. CAS

    cas 比较和替换,通过锁自旋的方式,来实现线程安全。 每次先取数据的值,然后比较是否已经发生修改,如果没有发生修改 就有权限去修改,如果发生了修改那么就进入自旋再次比较。

  9. 内存泄漏的解决办法

    控制变量的作用域,一旦确定后面不在使用 显式的赋值null 来帮助gc

  10. static关键字

    static 修饰变量 表示这个变量是一个类变量 存放在方法区

    static 修饰方法 表示这个方法是一个类方法

    static 修饰类 表示这个类是一个静态类。

    static 修饰代码块,表示是一个静态代码块,只有在类加载的时候被加载一次。

  11. 说一说ThreadLocal

    ThreadLocal 是一个线程本地变量,里面维护了一个ThreadLocalMap的一个对象,这个map的key 是实现了弱引用的ThreadLocal对象,value是你设置的值,一个强引用。在Thread类中的一个ThreadLocals 引用了这个对象,起到了一个线程隔离的效果。弱引用会在下一次gc的时候直接回收掉了。那么就会剩下一个空的entry 结点,如果没有调用remove或者set,get,方法就造成一个内存泄漏的情况。

  12. 线程池 几个参数

    核心线程数

    最大线程数

    阻塞队列

    线程工厂

    生存时间

    时间单位

    拒绝策略

  13. 弱引用 强引用

    弱引用对象会在下一次GC的时候直接清除了

    强引用则是不会被清除,JVM宁愿抛出OOM异常也不会。

  14. 接口和抽象类的区别

    接口被子类实现,抽象类被子类继承

    接口只能做方法声明 抽象类可以有方法声明也可以有方法实现

    接口中定义的变量只能是公共的静态常量,而抽象类中定义的变量就是普通变量

    抽象类中可以没有抽象方法。

    接口可以继承接口,并且可以多继承接口,但是类只有单继承。

  15. synchronized一直是重量级锁吗

    不是,jdk6 对synchronized 做了一个优化,引入了偏向锁和轻量级锁的一个锁升级的过程.

    最开始是无锁状态,然后进入同步代码块就默认变成一个偏向锁,把mark word 前54位记录成线程id ,然后倒数第三位偏向锁设置为1 代表使用偏向锁,如果又有一个线程来了,那么会升级为一个轻量级锁,轻量级锁 就是会申请一个 lock record 一个空间 来存储mark word 的拷贝,然后将lock Reocrd 中的owner 执行当前对象。JVM在利用cas的操作尝试将对象的mark word 更新为指向lock Record的指针,如果成功表示竞争到锁,则将锁标志位变成00 执行同步操作,如果失败判断当前对象的mark word是否指向当前线程的栈帧,如果是表示当前线程已经有当前对象的锁了,则直接执行同步代码块,如果不是只能说明该锁已经被其他线程给抢占到了,然后开始锁自旋就是开始一个忙等待的过程,到达了指定次数还是没有获取锁就直接膨胀,以前是默认是10次,现在由于引入了自适应自旋锁,自旋的时间就不是固定的了,而是由同一个锁上的自旋时间以及锁的拥有者的状态来决定。如果自旋完成后 还是没有获取锁,这轻量级锁需要膨胀为一个重量级的锁,锁标志位 变成10,后面等待的线程将会进入一个阻塞状态。

  16. 抽象类中有构造方法吗

    有构造方法,可以在子类中用super调用构造方法。

    但是如果是反射创建对象 则会抛出一个构造方法异常

  17. 说一下 Java 的垃圾回收机制

    minor gc 和 full gc 两种

    minor gc 主要负责回收年轻代的垃圾,full gc 则回收全部的垃圾

    因为对象都是在eden区创建,然后如果eden区满了就会触发一次minorgc 会清除eden区和当前使用的一个Survivor区,会把eden区和Survivor区的存活的对象用复制算法放入另一个Survivor区。分代年龄+1 如果分代年龄到达了15 就放入老年代

  18. JVM 的内存布局/内存模型。(需要详细到每个区放什么)

    线程隔离:

    ​ java虚拟机栈:

    ​ 栈帧: 局部变量表,动态链接,方法的返回地址

    ​ 本地方法栈:一样的

    ​ 程序计数器:用于记录程序运行到哪里

    线程共享:

    ​ 堆区: 对象的引用

    ​ 方法区: 类信息,常量,静态变量。

  19. JVM 的4种引用和使用场景?

    强引用:就是普通的对象,如果一直持有强引用,那么GC就不会回收,宁愿抛出OOM异常也不会回收

    软引用: 可以用于缓存,如果持有软引用对象,那么gc不会清除他 除非是快要抛出OOM异常了 就会清除。

    弱引用: 不太重要的对象,直接会被下一次gc 给清除了

    虚引用 : 和没有持有引用一样,只是会在被gc的时候通知一下。

  20. 说一下引用计数法与可达性分析算法。

    引用计数 就是 如果一个对象被另一个对象给引用着 那么引用+1

    可达性分析: 将一些可以作为gc roots的对象,作为根节点 一直遍历下去。最后得到一条引用链, 如果某些对象不在这个引用链上,那么说明这些对象是垃圾对象。

    gc roots对象:

    ​ 本地方法栈中JNT引用的对象

    ​ 方法区中的常量,静态变量引用的对象

    ​ java虚拟机栈中局部变量表引用的对象

  21. 如何判断对象是不是垃圾?

    用可达性分析 和引用计数

  22. 堆里面的分区和各自的特点。

    同上

  23. Minor GC 与 Full GC 分别在什么时候发生?

    Eden区满了,发生minor gc

    full gc 老年代满了 或者方法区满了

  24. 对象创建方法,对象的内存布局,对象的访问定位。

    对象创建的方法:

    当一个对象遇到一个new指令的时候,首先会检查这个指令的参数是否在常量池定位到一个类的符号引用,并检查这个引用是否被加载,连接,初始化了。如果没有就执行加载的过程。

    对象的内存布局:

    对象的内存中可以分为三个部分: 对象头,实例数据,对齐填充。

    对象头的第一部分用于存储对象自身的运行时数据,如对象的哈希码,GC分代年龄,锁状态标志,线程持有的锁等。

    另一部分是类型指针,即对象指向它的类元数据的指针,通过这个来确定这个对象是哪个类的实例。

    实例数据是对象真正存储的有效信息。

    对象的访问定位:

    使用句柄: java堆会划分一块内存作为句柄池,reference中存的是对象的句柄地址,而句柄中包含了对象的实例数据的地址和类型数据的地址(在方法区)

    优点: 对象被移动,reference不用修改,只会改变句柄中保存的地址.

    使用直接指针:

    ​ reference中存的是对象的地址,对象中分一小块内存保存类型数据的地址。优点:速度快。

  25. 说一下几种垃圾收集算法的原理和特点,应用的场景。怎么优化复制算法?

    标记–清除: 通过可达性分析得到垃圾对象,然后直接删除掉。会产生空间碎片,但是不用复制对象,可用于不会频繁发生gc的情景 老年代。

    标记–整理:通过可达性分析得到不是垃圾的对象,然后让他们往一边移动,然后删除边界以外的对象。老年代

    标记–复制: 通过可达性分析得到不是垃圾的对象,然后复制到另外一块区域,

    分代收集

  26. GC 收集器有哪些?CMS 收集器与 G1 收集器的特点。

    Serial收集器

    ParNew

    Parallel Scavenge

    Serial Old

    Parallel Old

    CMS

    G1

  27. 什么是内存泄露和内存溢出。

    java 如果不使用的对象,但是没有被gc 造成 一直在内存区域占用空间。

  28. 如何减少 gc 出现的次数(java 内存管理)。

    合理设计堆空间的大小,减少使用全局变量

  29. TCP连接建立,释放

    三次握手

    1. 客户端向服务器发送 SYN=1 Seq = x 发送完毕后 客户端进入 SYN_SEND状态
    2. 服务器向客户端发送 ACK=1 seq=y ACKnum = x+1 发送完毕 服务器进入SYN_RCVD状态
    3. 客户端在向服务器发送一个ACK=1 ACKnum = y+1 发送完毕 客户端进入一个ESTABLISHED 状态 服务器接收到这个数据包也进入ESTABLISHED 状态 握手完成 开始传输数据

    四次挥手

    1. 客户端向服务器发送一个 FIN=1 seq=x 发送完毕 客户端进入一个 FIN_WAIT_1 状态
    2. 服务器在向客户端发送一个 ACK=1 ACKnum= x+1 发送完毕 服务器进入一个 wait_close状态客户端接收到这个数据包就会变成FIN_WAIT_2状态
    3. 服务器在向客户端发送一个 FIN=1 seq =y 发送完毕 服务器进入一个last_ack状态
    4. 客户端接收以后 发送一个 ACK=1 ackNum=y+1 也进入一个Timewait状态 此时如果服务器接收到这个数据包 就进入close状态,客户端发送完毕后 等待2个MSL也进入close的状态
  30. JVM 常见的启动参数。

    -XMx JVM最大可用内存

    -XMN 年轻代代销

    -XSS 线程堆栈大小

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值