Java面试题
一、Java 基础
Java 内存模型(Java Memory model)
JMM 是一组抽象的概念不是真实存在,他描述了一组规则或规范,通过这组规范来限定程序中变量的访问方式。Java 是基于虚拟机运行,在虚拟机规范中,定义了一组规范来屏蔽掉硬件以及不同操作系统之间对访问内存的差异,使得Java程序在跨平台中内存访问得到一致。 Java 线程之间的通信是由JMM控制的
JVM运行程序的实体是线程,而每个线程创建时 JVM 都会为其创建一个工作内存(有些地方称为栈空间),用于存储线程私有的数据,而Java 内存模型中规定所有变量都存储在主内存,其主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存复制到自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,工作内存中存储这主内存中的变量副本拷贝,工作内存是每个线程的私有数据区域,因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成。
如果一个对象只是这个线程私有的,那么他会被分配到主内存还是仅仅在该线程的工作内存?
应该是分配在主内存,因为生成对象的时候并不知道该对象是否会被线程共享
![[Pasted image 20240812093554.png]]
如何控制变量在多线程之间共享
- 加锁:synchronized 关键,手动Lock等
- volatile:volatile 关键字实现了MESI(缓存一致性协议),可以让共享变量的变更体现在各个线程中
Java 并发编程
sleep 和 wait 方法的 区别
- sleep 是属于 Thread 类的,wait 是属于Object累的
- sleep 不会释放锁, wait 会释放锁
- sleep 可以在任何地方被调用,wait只能在同步代码块中被调用
synchronized 关键字如何实现的
- monitor 对象,加锁是monitorenter ,解锁是monitorexit
强引用,弱引用,虚引用,软引用
- 强引用: 内存不够的时候也不会释放,哪怕发生OOM
- 软引用:内存不够时GC就会释放
- 弱引用: 只要是GC 就会释放
- 虚引用:是最弱的引用,对对象无感有和没有一样,主要用来判断对象鉴活的应用,可以用来做对外内存的释放
ThreadLocal 会导致内存溢出,为什么
如果线程一直在使用,例如线程池中的线程,那么ThreadLocal引用的对象就不能被释放,导致内存泄漏
解决办法就是:在使用ThreadLcal 结束时调用remove 方法
框架
Redis
redis 数据结构
- String
- list
- set
- zset
- hash
redis 哨兵和集群模式
哨兵模式会有 哨兵服务器来监视 所有节点,检测健康,当主节点宕机之后,哨兵负责选举出新的主节点
集群模式 会将分为不同的hash槽,将不同槽对应不同的机器,然后根据key去路由到指定槽里,减轻单台服务器的压力
如果临时增加进来一个服务器怎么办?
会发生rehash,然后讲对应槽上的数据迁移过来
- 如何解决缓存穿透
https://zhuanlan.zhihu.com/p/58224918
缓存穿透就是,就是某些不在缓存中的key,导致不走缓存,被直接打上mysql,数据库压力过大。这里可以使用布隆过滤器,布隆过滤器的特点就是不存在的数据肯定返回不存在,存在的数据数据有可可能不存在
- 如何解决缓存雪崩
缓存雪崩就是 我们key设置的过期时间一样,导致在同一时间我们热点数据几乎同时失效导致,请求直接打到了数据库造成数据库压力大。
这个我们可以在设置过期时间时,加上一个随机数来使过期时间趋于分散,不会在同一时间失效
- 如何解决缓存击穿
和缓存雪崩大体一致,区别是缓存雪崩是大量的key,而缓存击穿是某一个key,当某个非常常用的热点数据过期的时候,此时恰好有大量的请求过来,发现缓存过期的时候就会直接访问数据库,导致在重新设置缓存之前有大量的请求进入数据库,导致数据库压力过大。
可以加锁,获取缓存时只有一个请求去获取
CAP理论
c: consistece 一致性
a: avaliable 可用性
p: partition tolerence 分区容忍
zookeeper
首先进入leader选举
先比较服务的 zxid(全局事务id) 最大的胜出,若相同然后比较 当前服务的id,id大的胜出,如果选举过半则直接成为leader,未过半则等待下一台服务加入进来
kafka
- 如果保持不会丢消息
producer在生产消息时设置必须等到所有节点都写入才会返回消息发送成功,也可以调整最小节点的数量
consumer 在消费消息的时候修改自动提交任务为手动提交任务,防止消息消费完后自动消费因网络抖动等原因导致的消费完成后未提交commit
- 如何保证不会重复消费
加一条位置的消息id,消费端来去重
- 如何分区
可以指定分区,或者指定key分区,根据key进行hash来分区