Java之面试题大全(持续更新ing)
2024-05-06 17:42:49 77 举报
AI智能生成
Java之面试题大全 整体概论 很全面(持续更新ing)
作者其他创作
大纲/内容
算法
线性表
数组
一维数组
双指针与滑动窗口
TCP发包
hystrix 限流
sentienl限流
二维数组
杨辉三角
螺旋
旋转
搜索
置零
链表
操作组合
链表反转
特殊线性表
Spring
Spring IOC的理解,原理与实现
总
IOC 就是控制反转,原来对象是由使用者来控制,有了spring之后,对象交由spring来控制管理
DI,依赖注入,把对应的属性值注入到对象中
比如通过注解的方式@Auotowired,完成属性的注入
比如通过注解的方式@Auotowired,完成属性的注入
IOC,它是一个容器,用来存储对象
使用map结构来存储,在spring中一般存在三级缓存,singletonObjects存放完整的bean对象
整个bean的生命周期,从创建到使用到销毁的过程全部都是由容器来管理(bean的生命周期)
使用map结构来存储,在spring中一般存在三级缓存,singletonObjects存放完整的bean对象
整个bean的生命周期,从创建到使用到销毁的过程全部都是由容器来管理(bean的生命周期)
分
1、一般聊ioc容器的时候要涉及到容器的创建过程(beanFactory,DefaultListableBeanFactory),向bean工厂中设置一些参数(BeanPostProcessor,Aware接口的子类)等等属性
2、加载解析bean对象,准备要创建的bean对象的定义对象beanDefinition,(xml或者注解的解析过程)
3、beanFactoryPostProcessor的处理,此处是扩展点,PlaceHolderConfigurSupport,ConfigurationClassPostProcessor
4、BeanPostProcessor的注册功能,方便后续对bean对象完成具体的扩展功能
5、通过反射的方式讲BeanDefinition对象实例化成具体的bean对象
6、bean对象的初始化过程(填充属性,调用aware子类的方法,调用BeanPostProcessor前置处理方法,调用init-mehtod方法,调用BeanPostProcessor的后置处理方法)
7、生成完整的bean对象,通过getBean方法可以直接获取
8、销毁过程
Spring初始化和创建对象流程
spring IOC的底层实现
反射
xml解析
设计模式
工厂模式
createBeanFactory
getBean,doGetBean,createBean,doCreateBean
createBeanInstance(getDeclaredConstructor,newinstance)
populateBean
initializingBean
getBean,doGetBean,createBean,doCreateBean
createBeanInstance(getDeclaredConstructor,newinstance)
populateBean
initializingBean
1、先通过createBeanFactory创建出一个Bean工厂(DefaultListableBeanFactory)
2、开始循环创建对象,因为容器中的bean默认都是单例的,所以优先通过getBean,doGetBean从容器中查找,找不到的话
3、通过createBean,doCreateBean方法,以反射的方式创建对象,一般情况下使用的是无参的构造方法(getDeclaredConstructor,newInstance)
4、进行对象的属性填充populateBean
5、进行其他的初始化操作(initializingBean)
bean的生命周期
1、实例化bean:反射的方式生成对象
2、填充bean的属性:populateBean(),循环依赖的问题(三级缓存)
3、调用aware接口相关的方法:invokeAwareMethod(完成BeanName,BeanFactory,BeanClassLoader对象的属性设置)
4、调用BeanPostProcessor中的前置处理方法:使用比较多的有(ApplicationContextPostProcessor
设置ApplicationContext,Environment,ResourceLoader,EmbeddValueResolver等对象)
设置ApplicationContext,Environment,ResourceLoader,EmbeddValueResolver等对象)
5、调用initmethod方法:invokeInitmethod(),判断是否实现了initializingBean接口,如果有,调用afterPropertiesSet方法,没有就不调用
6、调用BeanPostProcessor的后置处理方法:spring的aop就是在此处实现的,AbstractAutoProxyCreator
注册Destuction相关的回调接口:钩子函数
注册Destuction相关的回调接口:钩子函数
7、获取到完整的对象,可以通过getBean的方式来进行对象的获取
8、销毁流程,1;判断是否实现了DispoableBean接口,2,调用destroyMethod方法
Bean 的生命周期
Spring 是如何解决循环依赖的问题的
总
什么是循环依赖问题,A依赖B,B依赖A
分
先说明bean的创建过程:实例化,初始化(填充属性)
形成闭环的原因
1、先创建A对象,实例化A对象,此时A对象中的b属性为空,填充属性b
2、从容器中查找B对象,如果找到了,直接赋值不存在循环依赖问题(不通),找不到直接创建B对象
3、实例化B对象,此时B对象中的a属性为空,填充属性a
4、从容器中查找A对象,找不到,直接创建
循环依赖图
一级缓存
二级缓存
三级缓存
缓存的放置时间和删除时间
三级缓存:createBeanInstance之后:addSingletonFactory
二级缓存:第一次从三级缓存确定对象是代理对象还是普通对象的时候,同时删除三级缓存 getSingleton
一级缓存:生成完整对象之后放到一级缓存,删除二三级缓存:addSingleton
核心
实例化和初始化分开操作
Bean Factory与FactoryBean有什么区别
相同点
都是用来创建bean对象的
不同点
使用BeanFactory创建对象的时候,必须要遵循严格的生命周期流程,太复杂了
如果想要简单的自定义某个对象的创建,同时创建完成的对象想交给spring来管理,那么就需要实现FactroyBean接口了
isSingleton:是否是单例对象
getObjectType:获取返回对象的类型
getObject:自定义创建对象的过程(new,反射,动态代理)
getObjectType:获取返回对象的类型
getObject:自定义创建对象的过程(new,反射,动态代理)
Spring中用到的设计模式
单例模式
bean默认都是单例的
原型模式
指定作用域为prototype
工厂模式
BeanFactory
模板方法
postProcessBeanFactory,onRefresh,initPropertyValue
策略模式
XmlBeanDefinitionReader,PropertiesBeanDefinitionReader
观察者模式
listener,event,multicast
适配器模式
Adapter
装饰者模式
BeanWrapper
责任链模式
使用aop的时候会先生成一个拦截器链
代理模式
动态代理
委托者模式
delegate
Spring的AOP的底层实现原理
总
aop概念
应用场景
动态代理
分
aop是ioc的一个扩展功能,先有的ioc,再有的aop,只是在ioc的整个流程中新增的一个扩展点而已:BeanPostProcessor
1、代理对象的创建过程(advice,切面,切点)
2、通过jdk或者cglib的方式来生成代理对象
3、在执行方法调用的时候,会调用到生成的字节码文件中,直接回找到DynamicAdvisoredInterceptor类中的intercept方法,从此方法开始执行
4、根据之前定义好的通知来生成拦截器链
5、从拦截器链中依次获取每一个通知开始进行执行,在执行过程中,为了方便找到下一个通知是哪个,会有一个CglibMethodInvocation的对象,找的时候是从-1的位置一次开始查找并且执行的。
Spring的事务是如何回滚的
总
声明式事务
spring的事务是由aop来实现的,首先要生成具体的代理对象,然后按照aop的整套流程来执行具体的操作逻辑,正常情况下要通过通知来完成核心功能,但是事务不是通过通知来实现的,而是通过一个TransactionInterceptor来实现的,然后调用invoke来实现具体的逻辑
分
1、先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务
2、当需要开启的时候,获取数据库连接,关闭自动提交功能,开起事务
3、执行具体的sql逻辑操作
4、在操作过程中,如果执行失败了,那么会通过completeTransactionAfterThrowing看来完成事务的回滚操作,回滚的具体逻辑是通过doRollBack方法来实现的,实现的时候也是要先获取连接对象,通过连接对象来回滚
5、如果执行过程中,没有任何意外情况的发生,那么通过commitTransactionAfterReturning来完成事务的提交操作,提交的具体逻辑是通过doCommit方法来实现的,实现的时候也是要获取连接,通过连接对象来提交
6、当事务执行完毕之后需要清除相关的事务信息cleanupTransactionInfo
谈一下spring事务传播
7大传播特性
Required
Requires_new
nested
Support
Not_Support
Never
Mandatory
Requires_new
nested
Support
Not_Support
Never
Mandatory
事务嵌套
总
事务的传播特性指的是不同方法的嵌套调用过程中,事务应该如何进行处理,是用同一个事务还是不同的事务,当出现异常的时候会回滚还是提交,两个方法之间的相关影响,在日常工作中,使用比较多的是required,Requires_new , nested
分
1、先说事务的不同分类,可以分为三类:支持当前事务,不支持当前事务,嵌套事务
2、如果外层方法是required,内层方法是,required,requires_new,nested
3、如果外层方法是requires_new,内层方法是,required,requires_new,nested
4、如果外层方法是nested,内层方法是,required,requires_new,nested
REQUIRED和NESTED回滚的区别
在回答两种方式区别的时候,最大的问题在于保存点的设置,很多同学会认为内部设置REQUIRED和NESTED效果是一样的,其实在外层方法对内层方法的异常情况在进行捕获的时候区别很大,两者报的异常信息都不同,使用REQUIRED的时候,会报Transaction rolled back because it has been marked as rollback-only信息,因为内部异常了,设置了回滚标记,外部捕获之后,要进行事务的提交,此时发现有回滚标记,那么意味着要回滚,所以会报异常,而NESTED不会发证这种情况,因为在回滚的时候把回滚标记清除了,外部捕获异常后去提交,没发现回滚标记,就可以正常提交了。
REQUIRED_NEW和REQUIRED区别
这两种方式产生的效果是一样的,但是REQUIRED_NEW会有新的连接生成,而NESTED使用的是当前事务的连接,而且NESTED还可以回滚到保存点,REQUIRED_NEW每次都是一个新的事务,没有办法控制其他事务的回滚,但NESTED其实是一个事务,外层事务可以控制内层事务的回滚,内层就算没有异常,外层出现异常,也可以全部回滚。
Spring 系列图
redis
说一下你在项目中的redis的应用场景
数据结构
string
分布式锁
单值缓存
文章访问量
计数器
服务无状态
session共享
hash
list
set
zset
场景
redis是单线程还是多线程
无论什么版本,工作线程就是一个
6.x高版本出现了IO多线程
面向IO模型编程的时候,有内核的事,从内核把数据搬运到程序里这是第一步,然后,搬运回来的数据做的计算式第二步
单线程,满足redis的串行原子,只不过IO多线程后,把输入/输出放到更多的线程里去并行,好处如下:
1,执行时间缩短,更快;
2,更好的压榨系统及硬件的资源(网卡能够高效的使用)
1,执行时间缩短,更快;
2,更好的压榨系统及硬件的资源(网卡能够高效的使用)
redis存在线程安全的问题吗?为什么?
redis可以保障内部串行
外界使用的时候要保障,业务上要自行保障顺序
缓存现象
缓存穿透
key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。
key = null
布隆过滤器
缓存击穿
key对应的数据存在,但在redis中过期、从来没被缓存的,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮
缓存雪崩
当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。
Redis是怎么删除过期key的?
1,后台在轮询,分段分批的删除哪些过期的key
2,请求的时候判断时候已经过期了
尽量的把内存无用空间回收回来~!
2,请求的时候判断时候已经过期了
尽量的把内存无用空间回收回来~!
缓存如何回收的
1,后台在轮询,分段分批的删除哪些过期的key
2,请求的时候判断时候已经过期了
尽量的把内存无用空间回收回来~!
2,请求的时候判断时候已经过期了
尽量的把内存无用空间回收回来~!
缓存是如何淘汰的
0,内存空间不足的情况下:
1,淘汰机制里有不允许淘汰
2,lru/lfu/random/TTL
3,全空间
4,设置过过期的key的集合中
1,淘汰机制里有不允许淘汰
2,lru/lfu/random/TTL
3,全空间
4,设置过过期的key的集合中
如何进行缓存预热?
1,提前把数据塞入redis,(你知道那些是热数据吗?肯定不知道,会造成上线很多数据没有缓存命中)
2,开发逻辑上也要规避差集(你没缓存的),会造成击穿,穿透,雪崩,实施456中的锁方案
3,一劳永逸,未来也不怕了
2,开发逻辑上也要规避差集(你没缓存的),会造成击穿,穿透,雪崩,实施456中的锁方案
3,一劳永逸,未来也不怕了
数据库与缓存不一致如何解决?
1,redis是缓存,更倾向于稍微的有时差
2,还是减少DB的操作
3,真的要落地,咱就canal吧
简述一下主从不一致的问题?
1,redis的确默认是弱一致性,异步的同步
2,锁不能用主从(单实例/分片集群/redlock)==>redisson
3,在配置中提供了必须有多少个Client连接能同步,你可以配置同步因子,趋向于强制一性
4,wait 2 0 小心
描述一下redis持久化原理?
当前线程阻塞服务 不聊
异步后台进程完成持久
fork + cow
异步后台进程完成持久
fork + cow
Redis有哪些持久化方式?
1,RDB,AOF;主从同步也算持久化;
2,高版本:开启AOF,AOF是可以通过执行日志得到全部内存数据的方式,但是追求性能:
2.1,体积变大,重复无效指令 重写,后台用线程把内存的kv生成指令写个新的aof
2.2,4.x 新增更有性能模式:把重写方式换成直接RDB放到aof文件的头部,比2.1的方法快了,再追加日志
Redis也打不住了,万级流量会打到DB上,该怎么处理?
见456
redis中的事务三条指令式什么,第三条指令到达后执行失败了,怎么处理
redis实现分布式锁的指令
为什么使用setnx?
1,好东西,原子(不存在的情况下完成创建)
2,如果要做分布式锁,就要用set k v nx ex (不存在,过期时间,避免死锁)
分布式锁实现
jvm
描述一下jvm内存模型,以及这些空间的存放的内容
堆内存划分的空间,如何回收这些内存对象,有哪些回收算法?
如何解决线上gc频繁的问题
1. 查看监控,以了解出现问题的时间点以及当前FGC的频率(可对比正常情况看频率是否正常)
2. 了解该时间点之前有没有程序上线、基础组件升级等情况
3. 了解JVM的参数设置,包括:堆空间各个区域的大小设置,新生代和老年代分别采用了哪些垃
圾收集器,然后分析JVM参数设置是否合理。
圾收集器,然后分析JVM参数设置是否合理。
4. 再对步骤1中列出的可能原因做排除法,其中元空间被打满、内存泄漏、代码显式调用gc方法
比较容易排查。
比较容易排查。
5. 针对大对象或者长生命周期对象导致的FGC,可通过 jmap -histo 命令并结合dump堆内存文
件作进一步分析,需要先定位到可疑对象。
件作进一步分析,需要先定位到可疑对象。
6. 通过可疑对象定位到具体代码再次分析,这时候要结合GC原理和JVM参数设置,弄清楚可疑
对象是否满足了进入到老年代的条件才能下结论。
对象是否满足了进入到老年代的条件才能下结论。
描述一下class初始化过程
简述一下内存溢出的原因,如何排查线上问题
内存泄漏 VS 内存溢出
java.lang.OutOfMemoryError: ......java heap space..... 堆栈溢出,代码问题的可能性极大
java.lang.OutOfMemoryError: GC over head limit exceeded 系统处于高频的GC状态,而且
回收的效果依然不佳的情况,就会开始报这个错误,这种情况一般是产生了很多不可以被释放
的对象,有可能是引用使用不当导致,或申请大对象导致,但是java heap space的内存溢出
有可能提前不会报这个错误,也就是可能内存就直接不够导致,而不是高频GC.
回收的效果依然不佳的情况,就会开始报这个错误,这种情况一般是产生了很多不可以被释放
的对象,有可能是引用使用不当导致,或申请大对象导致,但是java heap space的内存溢出
有可能提前不会报这个错误,也就是可能内存就直接不够导致,而不是高频GC.
java.lang.OutOfMemoryError: PermGen space jdk1.7之前才会出现的问题 ,原因是系统的
代码非常多或引用的第三方包非常多、或代码中使用了大量的常量、或通过intern注入常量、
或者通过动态代码加载等方法,导致常量池的膨胀
代码非常多或引用的第三方包非常多、或代码中使用了大量的常量、或通过intern注入常量、
或者通过动态代码加载等方法,导致常量池的膨胀
java.lang.OutOfMemoryError: Direct buffer memory 直接内存不足,因为jvm垃圾回收不
会回收掉直接内存这部分的内存,所以可能原因是直接或间接使用了ByteBuffer中的
allocateDirect方法的时候,而没有做clear
会回收掉直接内存这部分的内存,所以可能原因是直接或间接使用了ByteBuffer中的
allocateDirect方法的时候,而没有做clear
java.lang.StackOverflowError - Xss设置的太小了
java.lang.OutOfMemoryError: unable to create new native thread 堆外内存不足,无法为
线程分配内存区域
线程分配内存区域
java.lang.OutOfMemoryError: request {} byte for {}out of swap 地址空间不够
jvm有哪些垃圾回收器,实际中如何选择
简述一下Java类加载模型?
JVM8为什么要增加元空间,带来什么好处
1、字符串存在永久代中,容易出现性能问题和内存溢出。
2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢
出,太大则容易导致老年代溢出。
出,太大则容易导致老年代溢出。
3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
元空间的特点
1,每个加载器有专门的存储空间。
2,不会单独回收某个类。
3,元空间里的对象的位置是固定的。
4,如果发现某个加载器不再存货了,会把相关的空间整个回收。
堆G1垃圾收集器有了解么,有什么特点
1. G1的设计原则是"首先收集尽可能多的垃圾(Garbage First)"。因此,G1并不会等内存耗尽(串
行、并行)或者快耗尽(CMS)的时候开始垃圾收集,而是在内部采用了启发式算法,在老年代找
出具有高收集收益的分区进行收集。同时G1可以根据用户设置的暂停时间目标自动调整年轻
代和总堆大小,暂停目标越短年轻代空间越小、总空间就越大;
行、并行)或者快耗尽(CMS)的时候开始垃圾收集,而是在内部采用了启发式算法,在老年代找
出具有高收集收益的分区进行收集。同时G1可以根据用户设置的暂停时间目标自动调整年轻
代和总堆大小,暂停目标越短年轻代空间越小、总空间就越大;
2. G1采用内存分区(Region)的思路,将内存划分为一个个相等大小的内存分区,回收时则以分
区为单位进行回收,存活的对象复制到另一个空闲分区中。由于都是以相等大小的分区为单位
进行操作,因此G1天然就是一种压缩方案(局部压缩);
区为单位进行回收,存活的对象复制到另一个空闲分区中。由于都是以相等大小的分区为单位
进行操作,因此G1天然就是一种压缩方案(局部压缩);
3. G1虽然也是分代收集器,但整个内存分区不存在物理上的年轻代与老年代的区别,也不需要
完全独立的survivor(to space)堆做复制准备。G1只有逻辑上的分代概念,或者说每个分区都
可能随G1的运行在不同代之间前后切换;
完全独立的survivor(to space)堆做复制准备。G1只有逻辑上的分代概念,或者说每个分区都
可能随G1的运行在不同代之间前后切换;
4. G1的收集都是STW的,但年轻代和老年代的收集界限比较模糊,采用了混合(mixed)收集的方
式。即每次收集既可能只收集年轻代分区(年轻代收集),也可能在收集年轻代的同时,包含部
分老年代分区(混合收集),这样即使堆内存很大时,也可以限制收集范围,从而降低停顿。
式。即每次收集既可能只收集年轻代分区(年轻代收集),也可能在收集年轻代的同时,包含部
分老年代分区(混合收集),这样即使堆内存很大时,也可以限制收集范围,从而降低停顿。
5. 因为G1建立可预测的停顿时间模型,所以每一次的垃圾回收时间都可控,那么对于大堆
(16G左右)的垃圾收集会有明显优势
(16G左右)的垃圾收集会有明显优势
介绍一下垃圾回收算法
Happens-Before规则
先行发生原则(Happens-Before)是判断数据是否存在竞争、线程是否安全的主要依据。
先行发生是Java内存,模型中定义的两项操作之间的偏序关系,如果操作A先行发生于操作B,
那么操作A产生的影响能够被操作B观察到。
先行发生是Java内存,模型中定义的两项操作之间的偏序关系,如果操作A先行发生于操作B,
那么操作A产生的影响能够被操作B观察到。
口诀:如果两个操作之间具有happen-before关系,那么前一个操作的结果就会对后面的一个操作可
见。是Java内存模型中定义的两个操作之间的偏序关系。
见。是Java内存模型中定义的两个操作之间的偏序关系。
常见的happen-before规则
1.程序顺序规则
一个线程中的每个操作,happen-before在该线程中的任意后续操作。(注解:如果只有一个线程的操
作,那么前一个操作的结果肯定会对后续的操作可见。)
程序顺序规则中所说的每个操作happen-before于该线程中的任意后续操作并不是说前一个操作必须要
在后一个操作之前执行,而是指前一个操作的执行结果必须对后一个操作可见,如果不满足这个要求那
就不允许这两个操作进行重排序
作,那么前一个操作的结果肯定会对后续的操作可见。)
程序顺序规则中所说的每个操作happen-before于该线程中的任意后续操作并不是说前一个操作必须要
在后一个操作之前执行,而是指前一个操作的执行结果必须对后一个操作可见,如果不满足这个要求那
就不允许这两个操作进行重排序
2.锁规则
对一个锁的解锁,happen-before在随后对这个锁加锁。(注解:这个最常见的就是synchronized方法和
syncronized块)
syncronized块)
3.volatile变量规则
对一个volatile域的写,happen-before在任意后续对这个volatile域的读。该规则在CurrentHashMap
的读操作中不需要加锁有很好的体现
的读操作中不需要加锁有很好的体现
4.传递性:
如果A happen-before B,且B happen-before C,那么A happen - before C.
5.线程启动规则
Thread对象的start()方法happen-before此线程的每一个动作。
6.线程终止规则
线程的所有操作都happen-before对此线程的终止检测,可以通过Thread.join()方法结束,
Thread.isAlive()的返回值等手段检测到线程已经终止执行。
Thread.isAlive()的返回值等手段检测到线程已经终止执行。
7.线程中断规则
对线程interrupt()方法的调用happen-before发生于被中断线程的代码检测到中断时事件的发生。
描述一下java类加载和初始化的过程?
加载,链接(验证,准备,解析),初始化,使用,卸载
加载
加载主要是将.class文件通过二进制字节流读入到JVM中。 在加载阶段,JVM需要完成3件事
1)通过classloader在classpath中获取XXX.class文件,将其以二进制流的形式读入内存。
2)将字节流所代表的静态存储结构转化为方法区的运行时数据结构;
3)在内存中生成一个该类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
链接
验证
主要确保加载进来的字节流符合JVM规范。验证阶段会完成以下4个阶段的检验动作
1)文件格式验证
2)元数据验证(是否符合Java语言规范)
3)字节码验证(确定程序语义合法,符合逻辑)
4)符号引用验证(确保下一步的解析能正常执行)
准备
准备是连接阶段的第二步,主要为静态变量在方法区分配内存,并设置默认初始值。
解析
解析是连接阶段的第三步,是虚拟机将常量池内的符号引用替换为直接引用的过程
初始化
初始化阶段是类加载过程的最后一步,主要是根据程序中的赋值语句主动为类变量赋值。
当有继承关系时,先初始化父类再初始化子类,所以创建一个子类时其实内存中存在两个对象实
例。
当有继承关系时,先初始化父类再初始化子类,所以创建一个子类时其实内存中存在两个对象实
例。
使用
程序之间的相互调用。
卸载
即销毁一个对象,一般情况下中有JVM垃圾回收器完成。代码层面的销毁只是将引用置为null。
JVM线上出OOM问题了如何定位?
吞吐量优先和响应时间优先的回收器是哪些?
吞吐量优先
Parallel Scavenge+Parallel Old(多线程并行)
响应时间优先
cms+par new(并发回收垃圾)
什么叫做阻塞队列的有界和无界,实际中有用过吗
ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列,线程池,生产者消费者
LinkedBlockingQueue:一个由链表结构组成的无界阻塞队列,线程池,生产者消费者
PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列,可以实现精确的定时任务
DelayQueue:一个使用优先级队列实现的无界阻塞队列,可以实现精确的定时任务
SynchronousQueue:一个不存储元素的阻塞队列,线程池
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列
LinkedBlockingDeque:一个由链表结构组成的双向无界阻塞队列,可以用在“工作窃取”模式
jvm监控系统是通过jmx做的么
内存屏障的汇编指令是啥
怎么提前避免内存泄漏
java基础
java的集合类
集合体系
高并发集合类,JUC
Hashmap为什么要使用红黑树
在jdk1.8版本后,java对HashMap做了改进,在链表长度大于8的时候,将后面的数据存在红黑树中,以加快检索速度
红黑树虽然本质上是一棵二叉查找树,但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。加快检索速率。
集合类是怎么解决高并发中的问题
哪些是非安全
线程非安全的集合类 ArrayList LinkedList HashSet TreeSet HashMap TreeMap 实际开发中我们自己用这样的集合最多,因为一般我们自己写的业务代码中,不太涉及到多线程共享同一个集合的问题
普通的安全的集合类
线程安全的集合类 Vector HashTable 虽然效率没有JUC中的高性能集合高,但是也能够适应大部分环境
JUC中高并发的集合类
ConcurrentHashMap
ConcurrentHashMap和HashTable的区别
ConcurrentHashMap线程安全的具体实现方式/底层具体实现
CopyOnWriteArrayList
简述一下自定义异常的应用场景
借助异常机制,我们可以省略很多业务逻辑上的判断处理,直接借助java的异常机制可以简化业务逻辑判断代码的编写
1当你不想把你的错误直接暴露给前端或者你想让前端从业务角度判断后台的异常,这个时候自定义异常类是你的不二选择
2 虽然JAVA给我们提供了丰富的异常类型,但是在实际的业务上,还有很多情况JAVA提供的异常类型不能准确的表述出我们业务上的含义
描述一下Object类中常用的方法
toString hashCode equals clone finalized wait notify notifyAll
toString
定义一个对象的字符串表现形式 Object类中定义的规则是 类的全路径名+@+对象的哈希码 重写之后 我们可以自行决定返回的字符串中包含对象的那些属性信息 …
clone
返回一个对象的副本 深克隆 浅克隆 原型模式 重写时实现Cloneable
finalized
GC 会调动该方法 自救
1.8的新特性有了解过吗
• Lambda表达式
• 函数式接口 函数式编程
• 方法引用和构造器调用
• Stream API
• 接口中的默认方法和静态方法
• 新时间日期API
Java面向对象的基本特征,继承、封装与多态,以及你自己的应用
引用拷贝 浅拷贝 深拷贝
引用拷贝即为赋值,指向同一地址
浅拷贝会创建新对象,但如果对象是引用类型实际仍为引用拷贝(重写clone方法)
深拷贝会完全复制整个对象,包括这个对象所包含的内部对象(重写clone方法)
重写和重载的区别
怎样声明一个类不会被继承,什么场景下会用
Java中的自增是线程安全的吗,如何实现线程安全的自增
Jdk1.8中的stream有用过吗,详述一下stream的并行操作原理?stream并行的线程池是从哪里来的
什么是ForkJoin框架 适用场景
Java种的代理有几种实现方式
equals()和==区别。为什么重写equal要重写hashcode
== 是运算符
== 可以用于基本数据类型和引用类型
== 可以用于基本数据类型和引用类型
== 两端如果是基本数据类型,就是判断值是否相同
equals来自于Object类定义的一个方法
equals只能用于引用类型
equals只能用于引用类型
equals在重写之后,判断两个对象的属性值是否相同
equals如果不重写,其实就是 ==
equals如果不重写,其实就是 ==
重写equals可以让我们自己定义判断两个对象是否相同的条件
Object中定义的hashcode方法生成的哈希码能保证同一个类的对象的哈希码一定是不同的
当equals 返回为true,我们在逻辑上可以认为是同一个对象,但是查看哈希码,发现哈希码不同,和equals方法的返回结果违背
当equals 返回为true,我们在逻辑上可以认为是同一个对象,但是查看哈希码,发现哈希码不同,和equals方法的返回结果违背
Object中定义的hashcode方法生成的哈希码跟对象的本身属性值是无关的
重写hashcode之后,我们可以自定义哈希码的生成规则,可以通过对象的属性值计算出哈希码
重写hashcode之后,我们可以自定义哈希码的生成规则,可以通过对象的属性值计算出哈希码
HashMap中,借助equals和hashcode方法来完成数据的存储
hashmap在1.8中做了哪些优化
hashmap线程安全的方式
方法一:通过Collections.synchronizedMap()返回一个新的Map,这个新的map就是线程安全的. 这个要求大家习惯基于接口编程,因为返回的并不是HashMap,而是一个Map的实现.
通过Collections.synchronizedMap()来封装所有不安全的HashMap的方法,就连toString, hashCode都进行了封装. 封装的关键点有2处,1)使用了经典的synchronized来进行互斥, 2)使用了代理模式new了一个新的类,这个类同样实现了Map接口.在Hashmap上面,synchronized锁住的是对象,所以第一个申请的得到锁,其他线程将进入阻塞,等待唤醒. 优点:代码实现十分简单,一看就懂.缺点:从锁的角度来看,方法一直接使用了锁住方法,基本上是锁住了尽可能大的代码块.性能会比较差.
方法二:重新改写了HashMap,具体的可以查看java.util.concurrent.ConcurrentHashMap. 这个方法比方法一有了很大的改进.
重新写了HashMap,比较大的改变有如下几点.使用了新的锁机制,把HashMap进行了拆分,拆分成了多个独立的块,这样在高并发的情况下减少了锁冲突的可能,使用的是NonfairSync. 这个特性调用CAS指令来确保原子性与互斥性.当如果多个线程恰好操作到同一个segment上面,那么只会有一个线程得到运行.
优点:需要互斥的代码段比较少,性能会比较好. ConcurrentHashMap把整个Map切分成了多个块,发生锁碰撞的几率大大降低,性能会比较好. 缺点:代码繁琐
优点:需要互斥的代码段比较少,性能会比较好. ConcurrentHashMap把整个Map切分成了多个块,发生锁碰撞的几率大大降低,性能会比较好. 缺点:代码繁琐
为什么hashmap扩容的时候是两倍
解决hash冲突的方式有哪些
开放定址法
所谓的开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入
再哈希法
再哈希法又叫双哈希法,有多个不同的Hash函数,当发生冲突时,使用第二个,第三个,….,等哈希函数计算地址,直到无冲突。虽然不易发生聚集,但是增加了计算时间。
链地址法
链地址法的基本思想是:每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被分配到同一个索引上的多个节点可以用这个单向 链表连接起来
建立公共溢出区
这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表
Tomcat为什么要重写类加载器
简单解释类加载器双亲委派
无法实现隔离性
无法实现热替换
简述一下Java运行时数据区
说一下反射,反射会影响性能吗
hashmap为什么用红黑树不用普通的AVL树
sleep 与 wait 区别
synchronized 和 ReentrantLock 的区别
Condition 类和Object 类锁方法区别
tryLock和Lock和lockInterruptibly 的区别
单例模式有哪些实现方式,有什么优缺点
多线程
如何预防死锁
死锁发生的是个必要条件
死锁预防,那么就是需要破坏这四个必要条件
多线程有哪几种创建方式
描述一下线程安全活跃态问题,竞态条件
Java中的wait和sleep的区别与联系?
描述一下进程与线程区别
描述一下Java线程的生命周期?
程序开多少线程合适
描述一下notify和notifyAll区别
描述一下synchronized和lock区别
简单描述一下ABA问题
实现一下DCL
实现一个阻塞队列(用Condition写生产者与消费者就)?
实现多个线程顺序打印abc
服务器CPU数量及线程池线程数量的关系
多线程之间是如何通信的?
描述一下synchronized底层实现,以及和lock的区别
synchronized关键字加在静态方法和实例方法的区别
countdownlatch的用法?
线程池问题:
Java多线程的几种状态及线程各个状态之间是如何切换的
如何在方法栈中进行数据传递
描述一下ThreadLocal的底层实现形式及实现的数据结构
Sychornized是否是公平锁?
Sychronized和ReentryLock的区别
线程池的创建方式、分类、应用场景、拒绝策略的场
景
景
描述一下锁的四种状态及升级过程
描述一下CMS和G1的异同
G1什么时候引发Full GC?
除了CAS,原子类,syn,Lock还有什么线程安全的方式?
描述一下HashMap和Hashtable的异同。
CAS的ABA问题怎么解决的?
描述一下AQS?
JUC包里的同步组件主要实现了AQS的哪些主要方法?
volatile的功能
volatile的可见性和禁止指令重排序怎么实现的?
简要描述一下ConcurrentHashMap底层原理?
网络和IO
网络
TCP三次握手
TCP四次分手
TCP连接状态
Connection refused
OSI七层参考模型
什么是长连接和短连接?有状态,无状态?
TCP是长连接吗?
IO
IO模型
BIO
NIO
AIO
同步阻塞,同步非阻塞
粘包,粘包,拆包
MySQL
数据库事务隔离级别
MVCC的实现原理
mysql幻读怎么解决的
sql join原理
数据库索引原理
底层索引数据结构
叶子节点存储的是什么
索引失效
mysql如何做分库分表的
数据存储引擎有哪些
InnoDB和MyISAM的区别
聚簇索引和非聚簇索引的区别
事务有哪些隔离级别,分别解决了什么问题
描述一下mysql主从复制的机制的原理?mysql主从复制主要有几种模式
如何优化sql,查询计划的结果中看哪些些关键数据
MySQL为什么选择B+树作为它的存储结构,为什么不选择Hash、二叉、红黑树
描述一下mysql的乐观锁和悲观锁,锁的种类
mysql原子性和持久性是怎么保证的
0 条评论
下一页