个人面试经验

1.锁、线程类型

1.使用过哪些Java开源框架?

spring,springBoot,mybatis,Springsecurity,redis,Log4j,SpringCloud

2.项目难点/亮点

用mybatis的类型转换器将javabean对应数据库中的vachar(json),自定义typeHandler实现TypeHandler方法,实现setParameter方法和getResult()方法。
setParameter()用于把Javabean设置到PrepareStatement的参数中。getResult()用于从ResultSet(根据列明或索引位置参数获取数据)或者CallableStatement(根据存储过程获取数据)中取出数据转换为Java对象。
数据自动渲染成单选多选这种题型的库是parse,github上别人写的

4.什么情况考虑多线程,什么情况考虑单线程?

计算型的程序多使用单线程
IO请求多的,使用多线程,来提高cpu的效率

为什么使用线程池?

在邮件服务器、文件服务器这些中,由于请求使用的是网络通讯协议,请求时间很久,单线程处理,系统等待时间过长。还
会出现如下情况:单个任务处理的时间很短而请求的数目却是巨大,cpu利用率很低。
而为每一个请求创建一个线程,线程创建,线程销毁。导致cpu开销太大,不可行。
所以使用线程池,维护固定的线程用来处理任务。
创建等待队列。采用任务太多等待队列满,任务溢出的处理策略。

mysql和tomcat连接池的配置

mysql中,最大链接数设置为cpu*2+磁盘数比较好
tomcat中,默认线程数为200.
		acceptCounts接受最大排队数是100,具体的还需要实测设置

线程越多越好吗?

不是越多越好,根据任务的性质,采取不同的策略。处理机个数为N
计算型性质的任务:采用N或者N+1获得cpu最大利用率。

IO性质的任务:大部分线程在等待IO输入,需要估算服务时间和等待时间,一般为N*2
最佳线程数目 = (线程等待时间与线程CPU计算时间之比 + 1)* CPU数目*(目标cpu的使用率)
混合型:具体视情况而定。

自动装箱、自动拆箱

装箱(包装):八大基本类型自动变成它的包装类
拆箱:将包装类自动转化为原址类型  Integer
自动装箱、自动拆箱是JDK1.5提供的功能。
自动装箱:可以把一个基本类型的数据直接赋值给对应的包装类型;
自动拆箱:可以把一个包装类型的对象直接赋值给对应的基本类型;
通过自动装箱、自动拆箱功能,可以大大简化基本类型变量和包装类对象之间的转换过程。比如,某个方法的参数类型为包装类型,调用时我们所持有的数据却是基本类型的值,则可以不做任何特殊的处理,直接将这个基本类型的值传入给方法即可。

内存溢出:

1.代码中存在死循环或者循环产生的对象过多。
2.内存从数据库中一次取出的数据过多。mybatis中使用Powbounds进行逻辑分页,实际将数据全部取出来,然后通过计算offset和limit,返回部分结果然后只返回想要的数据,造成内存溢出。
3集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;List,Map等集合对象使用后,对象的引用未删除,导致List,或者Map对象不能被jvm回收,如果list中存储数据很多,会造成内存泄漏。解决:对象使用后,及时删除引用。
4.内存参数设置太小。解决:修改jvm启动参数,增加内存大小。

如何实现原子性操作

1.对方法加锁 ReentrantLook锁和synchronized锁。使用锁机制
2.使用原子类AtomicoIntger,AtomicBoolean等,CAS机制就是,在一个死循环内,不断尝试修改目标值,直到修改成功。
3.使用volitale关键字实现同步(只能保证可见性,不保证原子性)
4.将变量定义为final属性,不可变就可以保证原子性了。

5.使用threadLocal保存变量

6.使用信号量机制。

ReentrantLook锁和synchronized锁区别

 1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。通过lock.lockInterruptibly()来实现这个机制。 
 2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。(公平锁按先后顺序唤醒线程)
 3.锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。

volatile关键字

volatile关键字 修饰共享变量后。
1.变量被修改立即写入主存。
2.变量被修改后,其他线程的缓存都作废掉。  保证了可见性
3.禁止重排序,执行到volatile变量时,其前面的所有语句都执行完,后面所有语句都未执行。
(在一定程度上保证了有序性)但是前面的语句的执行顺序不保证。
4.不能保证原子性。在多线程情况下依旧有可能出现写数据被覆盖的情况。
使用范围:
对volatile关键字的共享数据的操作是原子性操作。相比synchronized加锁机制,运行效率高

指令为什么要进行重排序?

一条指令执行步骤:取值、译码取寄存器中操作数、执行或计算、访问存储器、写回数据。
cpu执行指令:采用流水线的方式,提高cpu执行指令效率。禁止重排序是为了减少中断,提高性能、
重排序能减少一个指令等待其他指令完成而等待的时间。假设指令add等待指令load a 和load b完成才能执行,这时候add指令不能执行,可以重排序去执行其他指令。

Redis

redis是单线程的,为什么速度这么快?

纯内存操作,避免了多线程上下文切换的操作,切换上下文要进行中断处理。
核心是基于非阻塞的Io多路复用机制。创建多个socket进行Io操作,redis将这些socket置于队列中,由事件派发器去转发到对应的事件处理器。

redis常见数据结构

String:缓存、计数器、分布式锁等。
List:链表、队列、微博关注人时间轴列表等。
Hash:用户信息、Hash 表等。
Set:去重、赞、踩、共同好友等。无序集合,两种集合都键不能重复
Zset:访问量排行榜、点击量排行榜等。有序集合

Redis怎么保持缓存与数据库一致性?

使用策略:
1. 首先尝试从缓存读取,读到数据则直接返回;如果读不到,就读数据库,并将数据会写到缓存,并返回。
2. 需要更新数据时,先更新数据库,然后把缓存里对应的数据失效掉(删掉)。
需要解决的不一致,产生的原因是更新数据库成功,但是删除缓存失败。
解决方案:1给缓存设置过期时间。
		2定期全量更新等方法

resp协议

resp是序列化协议,将数据结构:字符串,错误类型,整数,数字进行序列化
是基于tcp连接方式,通过tcp传输数据,然后根据协议规则解析相应信息。
如:根据第一个自己判断他的数据类型。
特点:是二进制安全的,是redis客户端和redis服务器进行通讯的协议。
过程:redis客户端将命令作为bulk strings的resp数组发送给redis 服务器,服务器返回resp类型数据

https://zhuanlan.zhihu.com/p/101564435

JavaSe

Integer与int的区别

①int是java提供的8种原始数据类型之一。Java为每个原始类型提供了封装类,Integer是java为int提供的封装类。int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况,例如,要想表达出没有参加考试和考试成绩为0的区别,则只能使用Integer。
  • 封装类是一个类,有属性有方法。可以new一个实列。Boolean 是boolean 的实例化对象类

单精度浮点数float和双精度浮点数double

double 双精度,64位,1位符号位,11位指数位,52位小数.
flota 单精度浮点数,32位。举例:float a=3.5f;

初始化顺序

静态变量->静态代码块->非静态方法->构造方法,父类->子类

常见异常种类

NullPointExcepiton
SQLException
IoExeception
ClassNotFoundException
ClassCastException
DuplicationKeyException

Spring

AOP:jdk动态代理原理

动态代理的对象是在运行时期创建的,没办法通过断点查看,应该使用反编译为.class文件进行分析。
//将动态代理的class文件写入到磁盘中
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
分析: $Proxy0 默认继承了Proxy类。
1.为什么 JDK 动态代理要基于接口实现?而不是基于继承来实现?
因为 JDK 动态代理生成的对象默认是继承 Proxy ,Java 不支持多继承,所以 JDK 动态代理要基于接口来实现。
2.JDK 动态代理中,目标对象调用自己的另一个方法,会经过代理对象么?
内部调用的方法使用的是对象的本身,不会经过代理对象。
不拦截原因:动态生成代理对象实现了要拦截类的接口,重写了拦截了方法。而通过方法调用不走代理对象。
3.因为@Async,@Transctation也是通过aop动态代理实现的,所以如果通过其他方法引用,就不再经过代理对象,那么这些注解就会失效了。

jdk动态代理实现

1.需要接口,实现类
2.编写代理对象,继承InvocationHandler,代理类调用方法时会调用 InvocationHandler 的 invoke 方法。
给代理对象生成一个代理实列, 三个参数
         * 1.要代理对象的类加载器
         * 2.要代理对象的接口数组
         * 3.代理的动态处理器,即处理方法定义(自己理解)可以写lamda表达,用函数式编程,即继承了继承InvocationHandler的类,并实现invoke方法,对目标方法进行加强。
3.Proxy 是所有代理类的父类,它提供了一个静态方法 newProxyInstance 动态创建代理对象。

CGlib动态代理

1.首先实现一个MethodInterceptor,方法调用会被转发到该类的intercept()方法。
2.通过enhancer.create();创建代理对象。
特点:1.是外部引入的代理,需要引入包。
2.可以不同过接口的方式实现动态代理。
3.final方法是不能重载的,所以也不能通过CGLIB代理。

静态代理和动态代理的区别

静态代理:代理类由程序员编写,有源代码,并对其编译,在运行前,就有代理类的.class文件了。
动态代理:在程序运行时创建,提高了软件的可扩展性。

@ASync异步注解实现原理

Spring容器启动初始化Bean,先判断类中是否使用了@ASync注解的方法,如果有就创建切入点和切入点处理器(代理对象处理器),在调用@Async注解标注的方法时,会调用代理对象,执行切入点处理器的invoke()方法(在invoke方法里实现代理,并执行被代理对象本来的方法),将方法交给线程池执行,实现异步执行。

IOC的理解

1.Ioc容器
程序启动前扫描所有的bean放入ioc容器中。
ioc容器类似于一个map对象。Key-Value,需要时再取出来。
2.控制反转:引入ioc容器后,将对象之前的依赖关系,交由ioc容器去管理,所谓控制反转,就是本身对象之前的依赖关系由对象管理转为ioc管理,控制权变为ioc容器了。
3.依赖注入:通过依赖注入实现控制反转	,动态的将某种依赖关系注入到对象之中。

Spring mvc

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-48rIz9QN-1639207035170)(C:\Users\57281\AppData\Roaming\Typora\typora-user-images\image-20210822172429774.png)]

1.HandlerMapping 组件在项目启动中,扫描所有@RequestMapping的类存下路径信息。

2.DispatcherServlet的doDispatch方法会调用HandlerMapping protected HandlerExecutionChain getHandler(HttpServletRequest request)返回HandlerExecutionChain

3.HandlerExecutionChain 得到HandlerAdapter组件,这里面包含了controller,实际上执行者。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nL1PKf4Q-1639207035173)(C:\Users\57281\AppData\Roaming\Typora\typora-user-images\image-20210822170040470.png)]

GC

GC的基本原理:
1.对于程序员来说,用new关键字即在堆中分配了内存,我们称之为“可达”。对于GC来说,只要所有被引用的对象为null时,我们称之为“不可达”,就将进行内存的回收。
 2.当一个对象被创建时,GC开始监控这个对象的大小、内存地址及使用情况。GC采用有向图的方式记录和管理堆(heap)中的所有对象,通过这种方式可以明确哪些对象是可达的,哪些不是。当确定为不可达时,则对其进行回收。
 3.通过GC Roots进行可达性分析。
GC种类
Minor Gc年轻代的Gc,通常要求时间很短完成
Full Gc:老年代的Gc,耗时久,要求间隔时间越久越好。可能与Major Gc意思相同
都会stop the world 
从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。 Major GC 是清理永久代。Full GC 是清理整个堆空间—包括年轻代和永久代。

GC算法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E0BeW8sQ-1639207035174)(F:\qq下载\MobileFile\1625465588796.jpg)]

JVM模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uBxs7NHG-1639207035174)(C:\Users\57281\AppData\Roaming\Typora\typora-user-images\image-20210626164042271.png)]

本地方法栈作用:为使用本地native方法服务
栈帧:线程中一个方法生成一个栈帧,包含共享变量表,操作数栈,动态链接,方法出口 等。

动态链接:每一个方法(栈帧)都包含常量池中该方法的引用,通过动态链接将该引用由符号引用转化为可调用该方法的(名称)直接引用。

被所有方法线程共享的一块内存区域。
用于存储已经被虚拟机加载的类信息,常量,静态变量等。
这个区域的内存回收目标主要针对常量池的回收和堆类型的卸载

补充:不太重要

直接内存
直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机规范中定义的内存区域。
在 JDK 1.4 中新加入了 NIO,引入了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。

显然,本机直接内存的分配不会受到 Java 堆大小的限制,但是,既然是内存,肯定还是会受到本机总内存(包括 RAM 以及 SWAP 区或者分页文件)大小以及处理器寻址空间的限制。服务器管理员在配置虚拟机参数时,会根据实际内存设置 -Xmx 等参数信息,但经常忽略直接内存,使得各个内存区域总和大于物理内存限制(包括物理的和操作系统级的限制),从而导致动态扩展时出现 OutOfMemoryError 异常。

JVM参数

查看jvm重要参数   java -XX:+PrintCommandLineFlags -version      
初始堆内存:      (-XXS)InitialHeapSize=         程序启动时自动分配给jvm系统的内存大小,默认:物理内存的1/64(<1GB)
最大堆内存        缩写(XXS)MaxHeapSize       堆中对象最多占用的内存大小,如果经过full GC后还是大于此内存,就报内存溢出错误
物理内存的1/4
年轻代和老年比例   NewRatio=2(默认为2.即年轻代:比老年代=1:2)
年轻代中Eden区和survivor区比例:
				InitialSurvivorRatio=8(默认为8,因为有两个survivor区,所以即为Eden:from:to=8:1:1
线程栈内存大小(属于线程的空间大小)  VMThreadStackSize jdk8以后windos默认是0,linux默认是1024kb
打印垃圾收集器的详细信息       Java -XX:+PrintGCDetails
查看jvm参数信息              java -XX:+PrintFlagsFinal -version、
							java -XX:+PrintFlagsFinal -version | findstr /i "Ratio" 可以过滤字符
 -XX:MaxTenuringThreshold=0设置转化为老年代的次数大小为16次

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HRswLEYP-1639207035175)(C:\Users\57281\AppData\Roaming\Typora\typora-user-images\image-20210718175624269.png)]

设置堆大小

1.在idea中设置RunConfiguration中设置,只在次项目中起作用
2.在jdk中的.ini配置文件中设置,对所有项目都起作用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QuEjmJij-1639207035175)(C:\Users\57281\AppData\Roaming\Typora\typora-user-images\image-20210718180423389.png)]

计算机网络

一次完整的http请求过程

输入www.baidu.com
1.浏览器会查询本地DNS缓存,查找域名对应的ip地址。
2.没有则向DNS服务器请求解析域名,返回对应域名的ip地址,并保存到本地的DNS缓存中。此请求用的是UDP协议。
3.通过IP地址与目标服务器建立TCP链接,发送三次握手。
4.建立连接后,通过HTTP请求发送数据。http报文->tcp报文IP数据报->mac地址->目标主机
							  应用层->	传输层->网络层->数据链路层
http报文:请求头:目标主机、 accept:所能接受的数据类型。
		请求体

`

[外链图片转存中…(img-QuEjmJij-1639207035175)]

计算机网络

一次完整的http请求过程

输入www.baidu.com
1.浏览器会查询本地DNS缓存,查找域名对应的ip地址。
2.没有则向DNS服务器请求解析域名,返回对应域名的ip地址,并保存到本地的DNS缓存中。此请求用的是UDP协议。
3.通过IP地址与目标服务器建立TCP链接,发送三次握手。
4.建立连接后,通过HTTP请求发送数据。http报文->tcp报文IP数据报->mac地址->目标主机
							  应用层->	传输层->网络层->数据链路层
http报文:请求头:目标主机、 accept:所能接受的数据类型。
		请求体

https://blog.csdn.net/huangwei18351/article/details/81456228?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值