Java面试题(持续更新中...)
事务的四大特性原子性,隔离性,恒久性,同等性
事务的隔离级别和现象
[*]读未提交:可能产生脏读,读取到未提交的数据
[*]读已提交:可能产生不可重复读取问题,A事务中读取到B事务已提交的数据,导致两次读取数据不同等
[*]可重复读:可能产生幻读问题,A事务中查询到B事务插入的数据,导致两次查询条数不同等
[*]可序列化:最高级别,强制事务序列化执行,独占锁,并发效率慢
不可重复读和幻读的区别
不可重复读的重点在修改,两次查询数据不同
幻读的重点在新增和删除,两次查询行数不同
Spring怎样解决的循环依赖问题
首先说下什么是循环依赖:A对象依赖于B对象,B对象依赖于A对象。
Spring解决循环依赖的核心思想在于提前曝光,首先创建实例化A,并在三级缓存中保存实例化A的lambda表达式以便获取A实例,然后去实例化B,在实例化B的时候就可以取到A了,后面再去实例化A。
当我没有循环依赖和AOP时,这个三级缓存是没有在后续用到的。
线程有几个状态
6个状态分别是:新建,运行,阻塞,期待,超时期待,终止
wait和sleep的区别
[*]wait来自Object类,Sleep来自Thread类。
[*]wait会开释锁,sleep不会。
[*]wait必须在同步代码块中执行,sleep可以恣意执行。
[*]wait可以捕获非常,sleep必须捕获非常。
synchronized和lock锁的区别
sync可重入锁,不可中断,非公平锁
lock可重入锁,可以判断锁,非公平锁(可设置)
什么是可重入锁
只要持有该锁,再次进入代码块就不需要争抢锁,如递归,可以一直进进出出,不会出现死锁
工作中遇到过的非常
运行时非常,IO非常,数据库连接非常,ClassNotfound非常,OutOfMemoryError非常,ConcurrentModification并发修改非常
信号量和互斥锁的区别
信号量:一次可以被多个线程持有,资源调理
互斥锁:一次只能被一个线程持有,资源互斥
什么是AQS
抽象对象同步器,基于CLH队列(双向链表),用volatile修饰共享状态(state),线程通过CAS去改变状态符,成功则获取锁成功,失败则进入期待队列,期待被唤醒。
Executors线程池工厂的三大方法
newSingleThreadExecutor()单个线程池,newFixedThreadPool(n)创建固定大小的线程池,newCachedThreadPool()可伸缩的线程池
单例模式
饿汉式:直接创建对象。
懒汉式:利用时创建对象,双重检测锁和volatile关键字解决并发问题。
CAS(比较并交换—乐观锁)机制
比较当前工作内存中的值和主内存中的值,如果这个值是渴望的,则执行操作,否则不执行。
存在ABA狸猫换太子问题:
利用增加版本号可以解决,乐观锁机制
JUC提供了原子时间戳引用类AtomicStampedReference,可以解决ABA问题
怎么排查死锁问题
定位进程:jps -l
堆栈跟踪:jstack 进程号
JVM内存模型
[*]堆:内存对象
[*]栈:局部变量,方法出口,操作数,动态链接
[*]方法区(元空间):常量,静态变量,类信息
[*]本地方法栈:native方法
[*]程序计数器:反编译代码的执行顺序号
JVM参数介绍
-Xmx最大堆内存
-Xms初始堆内存
JVM垃圾接纳机制
JVM:年轻代内存满了之后会发生MINORGC,利用可达性分析算法,将引用的对象放入e0区,为引用的对象就进行minorgc垃圾接纳,每发生一次minorgc,存活对象会在s0和s1区进行切换,当s区满了和分代年岁15,会进入老年代,老年代满了会发生fullgc,如果fullgc也开释不了对象,而新对象一直在产生并放入老年代就会内存溢出OOM。
JVM调优:判断该服务业务代码会执行多少秒*每秒产生多少M的对象,并设置年轻代Eden(8:1:1)的大小(业务代码刚好执行完成,发生minorgc进行接纳),剩下的内存就分配给老年代。
G1网络器(C++语言实现),可以通过参数设置最大停顿时间,到达这个停顿时间就会发生gc,需要思量业务场景,避免对象过大或者年岁太大,多数对象进入老年代。
JVM垃圾接纳算法
[*]引用计数法:程序计数器
[*]年轻代-幸存者区:复制算法
[*]老年代:
[*]标记扫除(标记存活的对象,没有标记的对象进行扫除,会产生内存碎片)
[*]标记整理(标记存活的对象,将存活的对象移动到一端,没有标记的对象进行扫除,不会产生内存碎片)
为什么要设计STW(接纳时停顿)
如果没有,fullgc和minorgc时会误删除程序中的非垃圾对象。
s区的大对象(大于50%)会直接放去老年代。
minorgc和fullgc会产生STW。
为什么堆里面要划分年轻代和老年代?
答:如果不划分的话,垃圾对象一直堆积不接纳,等真正发生gc的时候,时间会超级长。
年轻代为什么要有s0和s1区
[*]如果没有的话会导致发生minorgc就把存活对象放入老年代了导致fullgc,停顿时间长
[*]如果只有一个s区,复制算法会产生内存碎片,eden区和s0区会互相复制,比如说eden和s0区各有存活的对象,eden将存活对象放入s0区,会导致内存不连续
[*]为什么要有两个区,颠末权衡后的最优解
JMM内存模型
紧张分为主内存(堆)和工作内存(栈),工作内存是主内存和一份拷贝,紧张操作有:锁定lock,解锁unlock,读取read,载入load,利用use,赋值assign,存储store,写入write
TCP三次握手
二次握手的问题:客户端的第一次请求时延误发送到了服务端,服务端成功接收到了请求(但在客户端以为这个请求已经失败了),第二次相应时服务端向客户端相应,客户端以为该请求已失败,并不会接收这次相应,服务端会一直死死的期待(死锁)客户端发送数据报文,造成资源斲丧(如果客户端重新建立连接,会建立一个新的通道,上一个通道会一直存在)。如果是三次握手的情况下,第三次握手如果服务端在一段时间内没接收到客户端的相应,就会关闭这个连接通道。
第一次握手,客户端向服务端发送请求建立连接。
第二次握手,服务端向客户端相应是否确认建立连接。
第三次握手,客户端会向服务端发送一个确认建立连接。
三次握手的目的:防止已失效的连接请求报文突然传送到了服务端
TCP四次挥手
由于TCP双向通道互相独立所导致的,
[*]c向s发送"我要关闭连接"。
[*]s向c发送"我知道了",并且s进入半关闭状态(可以接收数据,不可以发送数据)。
[*]s向c发送"我要断开连接了,你确认下",进入最后确认状态。
[*]c向s发送"可以断开",s接收到后会进行关闭连接,c期待2msl(数据报文一来一回的最大时间),进入关闭状态。
ArraysList扩容机制
默认初始容量10,扩容原始容量的1.5倍取整,扩容因子1
Vector向量扩容机制
线程安全sync锁
默认初始容量10,扩容原始容量的2倍取整,扩容因子1
HashMap扩容机制
默认初始容量16,扩容倍数2,扩容因子0.75
数组长度大于64并且链表长度大于等于8(每产生哈希冲突,进行equal比较,hash码相同更换,不同插入链表)->链表转变为红黑树,链表长度小于等于6则从红黑数转为链表,jdk1.7采用头插,jdk1.8采用尾插。
HashMap数据布局
HashMap的实现是基于数组和链表(或红黑树)的组合实现的。数组被初始化为肯定数量的桶,每个桶可以包含一个链表或者红黑树。当利用put()方法向HashMap中添加一个键值对时,首先会对键进行哈希计算,然后找到对应的桶。如果桶为空,就将键值对插入到桶中。如果桶不为空,就遍历桶中的全部键值对,查找是否已经存在相同的键,如果存在则更新值,否则将新的键值对插入到桶中。
ConcurrentHashMap数据布局
1.7 采用ReentrantLock+Segment+HashEntry分段锁的思想,对每个Segment桶位加锁。
1.8 舍弃了分段锁的思想,更加接近hashmap,采用synchronized+CAS+HashEntry+红黑树,对每个数组元素加锁
HashMap寻址
put方法实际有4个参数,第一个参数hash值是32位,左移16位并"高16位和低16位进行异或得到的值"让本就随机的值更加随机,尽量避免hash碰撞,进步查询效率。
HashMap为什么线程不安全
因为put方法执行的时候,首先要获取插入的位置索引,如果此时有另一个线程进入获取了同样的索引并插入,当前线程如果再插入会覆盖插入的数据,导致数据不同等
并发的三大特性
原子性,可见性,有序性
双亲委派机制
类加载器:BootStrapClassLoader主加载器,ExtClassLoader扩展加载器,AppClassLoader系统类加载器以及线程上下文加载器,可以自界说加载器。
双亲委派:向上委派到顶层加载器,向下查找加载路径
保卫线程
保卫线程最后关闭,保卫线程不可以用线程池创建,线程池创建的保卫线程都会转换成用户线程,保卫线程中创建线程,创建的照旧保卫线程
线程池执行流程
超过核心线程(甲方),就放入任务队列(排期),任务排不完,放入最大线程(外包),最大线程超过空闲时间,执行拒绝策略(辞退)
keep超时时间,最大线程中有线程空闲了,超过这个时间就接纳线程
线程池七大参数
[*]corePoolSize 线程池核心线程大小
[*]maximumPoolSize 线程池最大线程数量
[*]keepAliveTime 空闲线程存活时间
[*]unit 空闲线程存活时间单位
[*]workQueue 工作队列
[*]threadFactory 线程工厂
[*]handler 拒绝策略
[*]AbortPolicy:丢弃任务并抛出非常
[*]DiscardPolicy:静默丢弃任务,不抛非常
[*]DiscardOldestPolicy:丢弃最前面的任务,新任务加入队列
[*]CallerRunsPolicy:由调用线程执行该任务,不会丢弃
spring是什么
[*]是一个轻量级的简化开发的框架,管理Bean的容器,各个框架的中间人(整合各种框架)
[*]ioc容器用于管理bean,利用aop解决oop代码重复的问题
[*]springmvc是spring对web框架的一个解决方案,总前端控制器servlet视图解析器生成视图到页面。
[*]springboot是spring的快速开发包,相当于spring和springmvc的整合,约定大于配置。
spring对象的生命周期
[*]解析类得到BeanDefinition界说对象。
[*]推断构造方法。
[*]进行实例化,得到对象。
[*]给对象中的@Autowired注解属性赋值。
[*]回调Aware方法(获取容器,用于访问容器中其他的Bean)。
[*]调用初始化前的方法。
[*]调用初始化。
[*]调用初始化后的方法。
[*]将单例Bean放入单例池。
[*]利用Bean。
[*]销毁Bean。
bean的作用域
singleton单例,prototype多例,request一个请求一个单例,session一个session一个单例,application一个上下文一个单例,webSocket一个连接一个单例
spring的单例Bean是线程安全的吗
不是,框架并没有对多线程进行处置惩罚,利用双重检测锁和可见性关键字,ThreadLocal或者加锁。
spring的自动装配原理
@Import导入了扫描META-INFO/spring.factories文件,文件中配置了各个Starter中的配置类,配置类中利用@Bean注入,各个starter需要遵守springboot的约定
explain执行计划
紧张优化看type字段,执行效率:避免(All和index)All全表 Connection --> Channel --> 创建交换机 --> 创建队列 --> 队列绑定交换机 --> 发送消息/接收消息直接发送到队列:底层利用了默认交换机
</ul>RabbitMQ常见故障的解决思绪
https://cdn.nlark.com/yuque/0/2024/png/38795004/1716280601175-a089e4dd-226f-499d-8008-87e9f68992e0.png
RabbitMQ服务器宕机消息丢失
消息队列默认是恒久化到硬盘上的,不惧怕重启
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]