秋招---java相关面经整理

整理相关java面经,供自己和大家学习交流(持续更新中。。。)

1.为什要用springboot?启动流程(原理)?

1.1SpringBoot构建项目很方便,拥有强大融合社区开源软件的能力,拥有一套专业的开发流程,pring Boot 整合了主流的开源软件形成了一系列的 Starter,让我们有了一致的编程体验来集成各种软件,Spring Boot 在集成的时候做了大量的优化,让我们在集成的时候往往只需要很少的配置和代码就可以完成。
1.2启动流程链接:link

--------------------------------创建springbootApplication对象---------------------------------------------
1. 创建springbootApplication对象springboot容器初始化操作
2. 获取当前应用的启动类型。
	注1:通过判断当前classpath是否加载servlet类,返回servlet web启动方式。
	注2:webApplicationType三种类型:
		1.reactive:响应式启动(spring5新特性)
		2.none:即不嵌入web容器启动(springboot放在外部服务器运行 )
		3.servlet:基于web容器进行启动
3. 读取springboot下的META-INFO/spring.factories文件,获取对应的ApplicationContextInitializer装配到集合
4. 读取springboot下的META-INFO/spring.factories文件,获取对应的ApplicationListener装配到集合
5. mainApplicationClass,获取当前运行的主函数
6. 
7. 
------------------调用springbootApplication对象的run方法,实现启动,返回当前容器的上下文----------------------------------------------
8. 调用run方法启动
9. StopWatch stopWatch = new StopWatch(),记录项目启动时间
10. getRunListeners,读取META-INF/spring.factores,将SpringApplicationRunListeners类型存到集合中
11. listeners.starting();循环调用starting方法
12. prepareEnvironment(listeners, applicationArguments);将配置文件读取到容器中
		读取多数据源:classpath:/,classpath:/config/,file:./,file:./config/底下。其中classpath是读取编译后的,file是读取编译前的
		支持yml,yaml,xml,properties
13. Banner printedBanner = printBanner(environment);开始打印banner图,就是sprongboot启动最开头的图案
14. 初始化AnnotationConfigServletWebServerApplicationContext对象
15. 刷新上下文,调用注解,refreshContext(context);
16. 创建tomcat
17. 加载springmvc
18. 刷新后的方法,空方法,给用户自定义重写afterRefresh()
19. stopWatch.stop();结束计时
20. 使用广播和回调机制告诉监听者springboot容器已经启动化成功,listeners.started(context);
21. 使用广播和回调机制告诉监听者springboot容器已经启动化成功,listeners.started(context);
22. 返回上下文

2.redis持久化原理

-Redis提供了两种方式对数据进行持久化,分别是RDB和AOF。
-RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。
-AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾。Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。

3.如何解决Redis缓存击穿

----缓存击穿: 是指对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:如果这个key在大量请求同时进来之前正好失效,那么所有对这个key的数据查询都落到db,我们称为缓存击穿。
----与缓存雪崩的区别:
1.击穿是一个热点key失效
2. 雪崩是很多key集体失效
----如何解决?
使用分布式锁,使用互斥锁(mutex key)
(相关推荐)
缓存穿透解决方案:最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
缓存雪崩解决方案:大多数系统设计者考虑用加锁或者队列的方式

4.五层网络协议

link

5.应用层协议

FTP
SMTP、POP3
HTTP
DNS

6.如何实现一个安全的UDP?

如果要用udp实现可靠,那就必须要解决两个问题:丢包和包的顺序(包序)问题:在应用层实现

给数据包进行编号,按照包的顺序进行接收并存储

接收端收到数据包后,发送确认信息给发送端,发送端收到数据后再继续发送下一个包.如果接收端接收的数据包编号不是预期的编号,则要求发送端重新发送 (实现确认机制与重传机制)

已经实现udp可靠传输的协议:

RUDP:可靠数据报传输协议

RTP:实时传输协议,为数据提供了具有实时性的端对端传送服务

UDT:互联网传输协议,主要目的是支持高速广域网上的海量数据传输

7.static能修饰abstract类/方法吗?

不能,abstract是抽象类/方法,抽象类、方法不能被实例化

8.synchronized 和lock 还有 volatile的区别

---------------------------volatile和synchronized的区别 ----------------------------------------------
synchronized 关键字和 volatile 关键字是两个互补的存在,⽽不是对⽴的存在!
volatile 关键字是线程同步的轻量级实现,所以 volatile 性能肯定⽐ synchronized 关键字要好
。但是 volatile 关键字只能⽤于变量⽽ synchronized 关键字可以修饰⽅法以及代码块 。
volatile 关键字能保证数据的可⻅性,但不能保证数据的原⼦性。 synchronized 关键字两者都
能保证。
volatile 关键字主要⽤于解决变量在多个线程之间的可⻅性,⽽ synchronized 关键字解决的是
多个线程之间访问资源的同步性。

---------------------------synchronized 和Lock的区别------------------------------------------------
synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可);
Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

9.JVM双亲委派机制

link
加载器:

----Bootstrap ClassLoader:主要负责加载Java中的核心类,位于 %JRE_HOME%\lib 的rt.jar、resources.jar、charsets.jar和class等, 比如lang包,math包等等。
----Extension ClassLoader:主要负责加载 %JRE_HOME%\lib\ext 下的jar包和class文件。
----Application ClassLoader:主要负责加载当前应用的classpath下的所有类。
----User ClassLoader:用户自定义的类加载器,可以加载指定路径下的class文件。
双亲委派机制:当一个类加载器收到了类加载的请求后,它不会立刻去加载,而是把这个请求委派给它的父加载器去加载。只有当父加载器加载不了的时候,才由当前这个加载器去加载。
使用双亲委派机制的好处:
----通过委派的方式,可以避免类的重复加载。因为当父加载器成功加载一个类时,子加载器便不必再重复加载。
----通过这种方式可以保证系统安全性。比如如果黑客在你系统代码里自定义了一个有破坏功能的String类,在双亲委派的机制下,java.lang.String加载请求会向上一直被委派到Bootstrap ClassLoader,这个类加载器其实会去加载rt.jar包下的String类,也就是“正宗”的String类,从而达到了一个保护作用。

10.java类加载机制:到底能不能自己自定义java.lang.String类

----不可以加载自定义的java.开头的任何类。
----因为JDK已经在loadClass方法中帮我们实现了ClassLoader搜索类的算法,当在loadClass方法中搜索不到类时,loadClass方法就会调用findClass方法来搜索类,所以我们只需重写该方法即可。如没有特殊的要求,一般不建议重写loadClass搜索类的算法。
----如果不想打破双亲委派模型,那么只需要重写findClass方法即可
----如果想打破双亲委派模型,那么就重写整个loadClass方法

11.类加载顺序

记住 3 条原则:
1、父类优先于子类
2、属性优先于代码块优先于构造方法
3、静态优先于非静态
因此,类加载顺序为:
父类静态变量->
父类静态语句块->
子类静态变量->
子类静态语句块->
父类普通成员变量->
父类动态语句块->
父类构造器->
子类普通成员变量->
子类动态语句块->
子类构造器

12.JVM怎么给对象分配内存的?

JAVA中的对象都是在堆上进行分配的,当对象没有被引用时,需要进行CG进行回收内存,但是在对象数量非常多的时候,会进行对GC造成非常大的压力(频繁的进行GC,并且清理的对象数多),影响了应用的性能。在此基础上JVM针对性的进行优化,JVM通过逃逸分析来确定对象不会被外部访问,从而判断该对象可以在栈上分配内存,这样该对象所占用的内存空间就可以随着栈的销毁而销毁,减轻了垃圾回收的压力(GC)

13.Post,Get区别

----GET请求参数是通过URL进行传递的,POST请求的参数包含在请求体当中。
----GET请求比POST请求更不安全,因为参数直接暴露在URL中,所以,GET请求不能用来传递敏感信息。
----GET请求在url中传递的参数是有长度限制的(在HTTP协议中并没有对URL的长度进行限制,限制是特定的浏览器以及服务器对他的限制,不同浏览器限制的长度不同。),POST对长度没有限制。
----GET请求参数会完整的保留在浏览器的历史记录中,POST请求的参数不会保留。

14 说一说synchronized与Lock的区别

1.synchronized是Java关键字,在JVM层面实现加锁和解锁;Lock是一个接口,在代码层面实现加锁和解锁。

2.synchronized可以用在代码块上、方法上;Lock只能写在代码里。

3.synchronized在代码执行完或出现异常时自动释放锁;Lock不会自动释放锁,需要在finally中显示释放锁。

4.synchronized会导致线程拿不到锁一直等待;Lock可以设置获取锁失败的超时时间。

5.synchronized无法得知是否获取锁成功;Lock则可以通过tryLock得知加锁是否成功。

6.synchronized锁可重入、不可中断、非公平;Lock锁可重入、可中断、可公平/不公平,并可以细分读写锁以提高效率。

15 说一说synchronized的底层实现原理

1.synchronized作用在代码块时,它的底层是通过monitorenter、monitorexit指令来实现的。
monitorenter:
每个对象都是一个监视器锁(monitor),当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:
如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1。如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

monitorexit:
执行monitorexit的线程必须是objectref所对应的monitor持有者。指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个monitor的所有权。
monitorexit指令出现了两次,第1次为同步正常退出释放锁,第2次为发生异步退出释放锁。
2.方法的同步并没有通过 monitorenter 和 monitorexit 指令来完成,不过相对于普通方法,其常量池中多了 ACC_SYNCHRONIZED 标示符,JVM就是根据该标示符来实现方法的同步的。

16 谈谈ReentrantLock的实现原理

ReentrantLock是基于AQS实现的,AQS即AbstractQueuedSynchronizer的缩写,这个是个内部实现了两个队列的抽象类,分别是同步队列和条件队列。其中同步队列是一个双向链表,里面储存的是处于等待状态的线程,正在排队等待唤醒去获取锁,而条件队列是一个单向链表,里面储存的也是处于等待状态的线程,只不过这些线程唤醒的结果是加入到了同步队列的队尾,AQS所做的就是管理这两个队列里面线程之间的等待状态-唤醒的工作。

17公平锁与非公平锁是怎么实现的?

公平锁:按照线程等待顺序获取锁,一般将获取锁失败的线程放入等待队列中,每次从FIFO队列的队头取出线程获取锁。这种方式会造成性能低下,大量的时间花费在线程调度上。
非公平锁:不管等待顺序,每个线程获取锁的概率都是相等的,优点是提高了响应速度,不用把大量时间花费在线程调度上,而是花费在执行代码上。

18了解Java中的锁升级吗?

link

19说说你对AQS的理解

抽象队列同步器AbstractQueuedSynchronizer (以下都简称AQS),是用来构建锁或者其他同步组件的骨架类,减少了各功能组件实现的代码量,也解决了在实现同步器时涉及的大量细节问题,例如等待线程采用FIFO队列操作的顺序。在不同的同步器中还可以定义一些灵活的标准来判断某个线程是应该通过还是等待。

AQS采用模板方法模式,在内部维护了n多的模板的方法的基础上,子类只需要实现特定的几个方法(不是抽象方法!不是抽象方法!不是抽象方法!),就可以实现子类自己的需求。

基于AQS实现的组件,诸如:

ReentrantLock 可重入锁(支持公平和非公平的方式获取锁);

Semaphore 计数信号量;

ReentrantReadWriteLock 读写锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
java面经-百度准入职老哥整理.pdf》是一份关于百度准入职面试的Java面经整理。这份面经是由百度准入职的老哥整理而成,其中记录了一些面试时可能会遇到的问题以及解答方法。 这份面经对于准备参加百度准入职面试的人来说非常有价值。首先,它列出了一些常见的面试问题,涵盖了Java语言的各个方面,包括基础知识、数据结构与算法、设计模式、多线程、网络编程等等。通过仔细研究和复习这些问题的答案,可以帮助面试者全面了解Java语言的特性和应用。 其次,这份面经还提供了问题的解答思路和方法,帮助面试者理清思路,正确回答问题。这对于很多面试者来说特别有帮助,因为在面试时有时会遇到一些棘手的问题,有了这份面经的指导,面试者可以更好地掌握应对策略。 不过需要注意的是,面经作为一份参考资料,不能完全依赖于它来准备面试。面试官可能会问一些不在面经中列出的问题,因此考生还是需要自己对Java语言有充分的了解,并能够熟练运用。同时,面试官还会关注考生的沟通能力、解决问题的能力以及对新技术的学习和掌握能力。 总体来说,《java面经-百度准入职老哥整理.pdf》是一份非常宝贵的资料,可以帮助面试者对Java面试中可能会遇到的问题有更深入的了解,提供了解答思路和方法。但记住,面试准备还需要多方面的知识积累和实践经验的积累,才能在面试中展现自己的优势。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值