-
HashMap 与 ConcurrentHashMap有什么区别
HashMap和ConcurrentHashMap 最大的区别就是 ConcurrentHashMap是一个线程安全的map 而hashmap不是线程安全的。
而且concurrentHashMap是一个读写分离的模式,每次扩容的时候都让线程去帮忙扩容,而hashmap 还是正常库容,hashmap的get是从table中拿的。
-
HashMap 插入元素的过程
当触发一个put(key,value)方法的时候,他会调用一个putVal 方法 ,然后最开始获取到hashcode 如果key是null 那么直接获取0 而不计算。然后根据路由算法 hash & length -1 得到一个索引值,然后根据索引值查找头结点有无数据,如果没有数据就直接插在头结点,如果有数据就一直遍历 看是不是链表,如果是链表就插入到末尾,在其中都会判断是否有key存在,如果存在就用newValue 替换oldValue,如果不是链表那就走红黑树的插入逻辑。
-
interface 是什么?用 interface 有什么好处
interface 是jvm的关键字,标识某个类是一个接口
接口实现了对修改封闭,对扩展开发的原则。当你要扩展功能的时候,不用修改现有的设计的类,直接实现某个接口的类就可以了。
-
Java 有内存泄露吗
有,比如ThreadLocal中维护的ThreadLocalMap 的key是一个实现了虚引用的对象,而value是一个强引用对象。
如果发生了一次gc 那么虚引用对象被回收了 那么map里面就有了一个key为null的entry。都知道threadLocalMap是会随着Thread类的消亡而消亡的,那么这么null的entry 也会跟着Thread消亡而消亡,此时就发生内存泄漏
-
ArrayList与 LinkedList 有什么区别
ArrayList 底层是数组实现的,需要扩容 每次库容1.5倍 提供随机访问
LinkedList 底层是链表实现的,不需要扩容 添加删除的效率比ArrayList快
-
volatile 关键字有什么作用
volatile关键字修饰的变量,保证了变量的可见性,禁止指令重排,有序性。
-
synchronized 和 reentrantlock` 的区别
synchronized 是JVM提供的关键字,不可中断 只提供非公平锁,不需要手动释放锁 不可知道是否获取到锁 一直阻塞
reentranlock 是API层面的锁,可中断 提供了非公平和公平锁的两种实现, 需要手动释放锁 可以知道是否获取到锁, 锁超时
-
CAS
cas 比较和替换,通过锁自旋的方式,来实现线程安全。 每次先取数据的值,然后比较是否已经发生修改,如果没有发生修改 就有权限去修改,如果发生了修改那么就进入自旋再次比较。
-
内存泄漏的解决办法
控制变量的作用域,一旦确定后面不在使用 显式的赋值null 来帮助gc
-
static关键字
static 修饰变量 表示这个变量是一个类变量 存放在方法区
static 修饰方法 表示这个方法是一个类方法
static 修饰类 表示这个类是一个静态类。
static 修饰代码块,表示是一个静态代码块,只有在类加载的时候被加载一次。
-
说一说ThreadLocal
ThreadLocal 是一个线程本地变量,里面维护了一个ThreadLocalMap的一个对象,这个map的key 是实现了弱引用的ThreadLocal对象,value是你设置的值,一个强引用。在Thread类中的一个ThreadLocals 引用了这个对象,起到了一个线程隔离的效果。弱引用会在下一次gc的时候直接回收掉了。那么就会剩下一个空的entry 结点,如果没有调用remove或者set,get,方法就造成一个内存泄漏的情况。
-
线程池 几个参数
核心线程数
最大线程数
阻塞队列
线程工厂
生存时间
时间单位
拒绝策略
-
弱引用 强引用
弱引用对象会在下一次GC的时候直接清除了
强引用则是不会被清除,JVM宁愿抛出OOM异常也不会。
-
接口和抽象类的区别
接口被子类实现,抽象类被子类继承
接口只能做方法声明 抽象类可以有方法声明也可以有方法实现
接口中定义的变量只能是公共的静态常量,而抽象类中定义的变量就是普通变量
抽象类中可以没有抽象方法。
接口可以继承接口,并且可以多继承接口,但是类只有单继承。
-
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,后面等待的线程将会进入一个阻塞状态。
-
抽象类中有构造方法吗
有构造方法,可以在子类中用super调用构造方法。
但是如果是反射创建对象 则会抛出一个构造方法异常
-
说一下 Java 的垃圾回收机制
minor gc 和 full gc 两种
minor gc 主要负责回收年轻代的垃圾,full gc 则回收全部的垃圾
因为对象都是在eden区创建,然后如果eden区满了就会触发一次minorgc 会清除eden区和当前使用的一个Survivor区,会把eden区和Survivor区的存活的对象用复制算法放入另一个Survivor区。分代年龄+1 如果分代年龄到达了15 就放入老年代
-
JVM 的内存布局/内存模型。(需要详细到每个区放什么)
线程隔离:
java虚拟机栈:
栈帧: 局部变量表,动态链接,方法的返回地址
本地方法栈:一样的
程序计数器:用于记录程序运行到哪里
线程共享:
堆区: 对象的引用
方法区: 类信息,常量,静态变量。
-
JVM 的4种引用和使用场景?
强引用:就是普通的对象,如果一直持有强引用,那么GC就不会回收,宁愿抛出OOM异常也不会回收
软引用: 可以用于缓存,如果持有软引用对象,那么gc不会清除他 除非是快要抛出OOM异常了 就会清除。
弱引用: 不太重要的对象,直接会被下一次gc 给清除了
虚引用 : 和没有持有引用一样,只是会在被gc的时候通知一下。
-
说一下引用计数法与可达性分析算法。
引用计数 就是 如果一个对象被另一个对象给引用着 那么引用+1
可达性分析: 将一些可以作为gc roots的对象,作为根节点 一直遍历下去。最后得到一条引用链, 如果某些对象不在这个引用链上,那么说明这些对象是垃圾对象。
gc roots对象:
本地方法栈中JNT引用的对象
方法区中的常量,静态变量引用的对象
java虚拟机栈中局部变量表引用的对象
-
如何判断对象是不是垃圾?
用可达性分析 和引用计数
-
堆里面的分区和各自的特点。
同上
-
Minor GC 与 Full GC 分别在什么时候发生?
Eden区满了,发生minor gc
full gc 老年代满了 或者方法区满了
-
对象创建方法,对象的内存布局,对象的访问定位。
对象创建的方法:
当一个对象遇到一个new指令的时候,首先会检查这个指令的参数是否在常量池定位到一个类的符号引用,并检查这个引用是否被加载,连接,初始化了。如果没有就执行加载的过程。
对象的内存布局:
对象的内存中可以分为三个部分: 对象头,实例数据,对齐填充。
对象头的第一部分用于存储对象自身的运行时数据,如对象的哈希码,GC分代年龄,锁状态标志,线程持有的锁等。
另一部分是类型指针,即对象指向它的类元数据的指针,通过这个来确定这个对象是哪个类的实例。
实例数据是对象真正存储的有效信息。
对象的访问定位:
使用句柄: java堆会划分一块内存作为句柄池,reference中存的是对象的句柄地址,而句柄中包含了对象的实例数据的地址和类型数据的地址(在方法区)
优点: 对象被移动,reference不用修改,只会改变句柄中保存的地址.
使用直接指针:
reference中存的是对象的地址,对象中分一小块内存保存类型数据的地址。优点:速度快。
-
说一下几种垃圾收集算法的原理和特点,应用的场景。怎么优化复制算法?
标记–清除: 通过可达性分析得到垃圾对象,然后直接删除掉。会产生空间碎片,但是不用复制对象,可用于不会频繁发生gc的情景 老年代。
标记–整理:通过可达性分析得到不是垃圾的对象,然后让他们往一边移动,然后删除边界以外的对象。老年代
标记–复制: 通过可达性分析得到不是垃圾的对象,然后复制到另外一块区域,
分代收集
-
GC 收集器有哪些?CMS 收集器与 G1 收集器的特点。
Serial收集器
ParNew
Parallel Scavenge
Serial Old
Parallel Old
CMS
G1
-
什么是内存泄露和内存溢出。
java 如果不使用的对象,但是没有被gc 造成 一直在内存区域占用空间。
-
如何减少 gc 出现的次数(java 内存管理)。
合理设计堆空间的大小,减少使用全局变量
-
TCP连接建立,释放
三次握手
- 客户端向服务器发送 SYN=1 Seq = x 发送完毕后 客户端进入 SYN_SEND状态
- 服务器向客户端发送 ACK=1 seq=y ACKnum = x+1 发送完毕 服务器进入SYN_RCVD状态
- 客户端在向服务器发送一个ACK=1 ACKnum = y+1 发送完毕 客户端进入一个ESTABLISHED 状态 服务器接收到这个数据包也进入ESTABLISHED 状态 握手完成 开始传输数据
四次挥手
- 客户端向服务器发送一个 FIN=1 seq=x 发送完毕 客户端进入一个 FIN_WAIT_1 状态
- 服务器在向客户端发送一个 ACK=1 ACKnum= x+1 发送完毕 服务器进入一个 wait_close状态客户端接收到这个数据包就会变成FIN_WAIT_2状态
- 服务器在向客户端发送一个 FIN=1 seq =y 发送完毕 服务器进入一个last_ack状态
- 客户端接收以后 发送一个 ACK=1 ackNum=y+1 也进入一个Timewait状态 此时如果服务器接收到这个数据包 就进入close状态,客户端发送完毕后 等待2个MSL也进入close的状态
-
JVM 常见的启动参数。
-XMx JVM最大可用内存
-XMN 年轻代代销
-XSS 线程堆栈大小
Java每日30面试题---2020年9月22日
最新推荐文章于 2023-02-22 22:59:16 发布