java面试题

redis

redis使用场景?

string、list(队列)、hash(hmset)、set(统计网站访问ip)、zset(top10)
缓存、服务无状态化、锁(redison)
及时性、数据一致性要求不高的数据、访问量大更新频率低的

redis单线程还是多线程?

无论什么版本,工作线程只有一个。
6.X版本出现了IO多线程(redis性能瓶颈在网络请求、所以使用多线程处理io 如:用户空间内、内核空间以及网卡的输入输出,单线程处理数据的计算)

遇到过缓存穿透吗?

当key不存在时,直接查db
解决:
1.value为null的key也放入缓存,设置一个过期时间
2.使用布隆过滤器

遇到过缓存击穿吗?

对一个热点key,非常热,key过期后会有大量请求直接落到db
解决:1.查缓存没有
2.1获取到锁:查db
2.2未获取到锁:sleep一会,回到步骤1
3.更新db到缓存
4.解锁
sleep是blocking状态,不会抢占cpu时间,做好线程池管理就行了

如何避免缓存雪崩?

当key过期时间一样时 所有的key统一过期
解决:过期时间使用随机值

缓存回收策略?

1.后台在轮询的时候,分段删除过期key
2.请求的时候判断已过期的
3.内存空间不足的情况下
4.lru ttl random lfu

如何进行缓存预热?

提前把数据存入redis,你知道哪些是热数据吗?
不知道哪些是热数据情况下,结合缓存击穿策略来回答

数据库与缓存不一致?

1.canal+binlog+rocketmq顺序消费+重试+时间版本号

redis主从不一致问题?

1.redis默认弱一致的,异步同步
2.锁不能用主从,可以用单实例、分片集群 ==> redisson
3.wait 2 0同步复制完返回,不推荐

redis持久化原理

RDB AOF(默认1秒fsync一个pageCache)
开启AOF是可以通过执行日志得到全部内存数据的方式
aof文件体积会变大、重复无效命令,重写所有的kv生成命令到aof
4.X版本,重写不再生成kv命令(性能原因),改为把rdb文件放到aof文件的头部,再追加日志

redis扛不住了,万级流量达到DB上

回答缓存穿透

为什么使用setnX?

原子性的,不存在则完成创建

分布式锁?

lua脚本单线程+ set NX EX命令 不存在则设置 +过期时间
NX EX要在同一个原子内执行避免死锁
redisson 分布式锁,读写锁、countdownLatch 、 semaphore等
如果未设置过期时间、线程未结束可以自动续期、默认30秒

redis存储

1.redis实例哈希槽slots ,有利于数据迁移
2.一致性hash算法,有利于负载防止hash倾斜,且添加移除节点只有影响下一个node节点的查询
https://zhuanlan.zhihu.com/p/179266232


jvm模型?

在这里插入图片描述

— 线程独享区—

  • 每个线程都有自己的栈,栈中的数据都是以栈帧(一个方法)的格式存在。
  • 在这个线程上正在执行的每一个方法都各自对应一个栈帧
  • 栈帧是一个内存区块,是一个数据集维系着方法执行过程中的各种数据信息

程序计数器

  • 是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

本地方法栈

(Native MethodStacks):

  • 与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。

— 共享区—

方法区

存放class文件、常量

存放共享对象、大对象
默认新生代空间的分配:Eden : Fron : To = 8 : 1 : 1
新生带,默认15Minor GC ->老年代 Full GC
* 垃圾回收算法
根搜索算法、标记清除(易产生磁盘碎片)、复制算法、标记整理算法(被引用对象左端移动)
对于新生代内存的回收(Minor GC)主要采用复制算法。而对于老年代的回收(Major GC),大多采用标记-整理算法。
CMS收集器在Minor GC时会暂停所有的应用线程,并以多线程的方式进行垃圾回收
* 垃圾收集器
CMS才要采用多线程标记清除算法、后会产生大量的内存碎片,当有不足以提供整块连续的空间给新对象/晋升为老年代对象时又会触发FullGC。且在1.9后将其废除
G1从整体上来看是基于‘标记-整理’算法实现,从局部(相关的两块Region)上来看是基于‘复制’算法实现,这两种算法都不会产生内存空间碎片。
可以并行回收各个region空间,不停止应用线程
并行:两个cpu分别执行两个任务
并发:两个cpu执行3+任务

执行引擎

解释执行字节码指令、优化热点字节码为指令、垃圾回收

  • 解释器
  • JIT即时编译
  • GC

类加载器

一、类加载流程

  • 加载–>连接(验证–>准备–>解析)–>初始化。
  • 1.加载
    这个过程主要是通过类的全限定名,例如 java.lang.String 这样带上包路径的类名,获取到字节码文件;然后将这个字节码文件代表的静态存储结构(可简单理解为对象创建的模板)存在方法区,并在堆中生成一个代表此类的 Class 类型的对象,作为访问方法区中“模板”的入口,往后创建对象的时候就按照这个模板创建。举个例子,有时候通过反射创建对象,像当初学 JDBC 时会通过 Class.getName(“com.mysql.jdbc.Driver.class”).newInstance() 创建对象,通过 Class 和相应的全限定类名获取到方法区中的“模板”然后创建对象。
    在这里插入图片描述
  • 2、验证
    验证过程主要确保被加载的类的正确性。首先要先验证文件格式是否规范,如果只是通过 .class 后缀来辨别,那随便把后缀名改一下就可以跑程序了,那岂不是很容易出事。
  • 3、准备与初始化
    这个阶段主要是给类变量(静态变量)分配方法区的内存并初始化类对象,放入方法区

二、类加载器分类

在这里插入图片描述
启动类加载器是由C/C++写的,主要负责加载 jre\lib 目录下的类;扩展类加载器主要负责加载 jre\lib\ext 目录下的类;而应用程序类加载器主要负责加载我们自己编写的类;当然还能自己写类加载器,即自定义加载器。程序主要由前面三个类加载器相互配合加载的。

三、类加载时机

创建类的实例,也就是new一个对象
访问某个类或接口的静态变量,或者对该静态变量赋值
调用类的静态方法
反射(Class.forName(“com.lyj.load”))
初始化一个类的子类(会首先初始化子类的父类)
JVM启动时标明的启动类,即文件名和类名相同的那个类

jvm 对象内存分配

栈上分配-> tlab分配->eden区分配->老年代
  栈上分配:
	-XX:+DoEscapeAnalysis 是开启逃逸分析 默认就是打开的
	对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值