提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
一、面试
1.SpringMVC的执行流程
1.用户发送请求到前端控制器DispatcherServlet;
2.前端控制器DispatcherServlet收到请求调用HandlerMappering处理器映射器;
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
2.线程与进程的关系
每一个进程中都至少包含最少一个线程,线程是进程中执行运算的最小单位,也是执行处理机调度的基本单位。
每一个进程中都有自己的地址空间,如内存、cpu等。进程是资源分配的最小单位。
当我们对资源的保护管理要求比较高的时候,建议使用多进程,当然存在的开销也会比较大,反过来,如果频繁切换下,对资源的保护管理要求不那么高,或者开销有限,使用多线程会比较方便。
3.java的线程状态
共有六种状态
new(新建状态),runnable(就绪状态和运行状态),blocked(阻塞状态),waiting(阻塞状态),timed waiting(阻塞状态),terminated(终止状态)
需要注意的是在new 完之后 ,调用start()方法之后并不代表执行run方法。而是进入就绪状态等待cpu的调度。
1,当进入synchronized同步代码块或同步方法时,且没有获取到锁,线程就进入了blocked状态,直到锁被释放,重新进入runnable状态
2,当线程调用wait()或者join时,线程都会进入到waiting状态,当调用notify或notifyAll时,或者join的线程执行结束后,会进入runnable状态
3,当线程调用sleep(time),或者wait(time)时,进入timed waiting状态,当休眠时间结束后,或者调用notify或notifyAll时会重新runnable状态。
4,程序执行结束,线程进入terminated状态
补充:关于notify与notifyAll的区别
java中提供了两种方法来唤醒在某些条件下等待的线程,可以用这两个的任意一个。需要注意的是:
当你使用notify时,会随机唤醒一个线程。注意是随机。
当使用notifyAll时,会唤醒所有的线程。
知乎上看到的:
先说两个概念:锁池和等待池
锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象
的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中Reference:java中的锁池和等待池
然后再来说notify和notifyAll的区别 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
综上,所谓唤醒线程,另一种解释可以说是将线程由等待池移动到锁池,notifyAll调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。
而notify只会唤醒一个线程。有了这些理论基础,后面的notify可能会导致死锁,而notifyAll则不会的例子也就好解释了
4.java反射
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
具体的应用比如说spring的依赖注入,拦截器等。
5.如何创建自定义注解
java.lang.annotation中提供了元注解,可以使用这些注解来定义自己的注解。主要使用的是Target和Retention注解
java.lang.reflect.AnnotationElement接口则提供了功能可以拿到我们定义的注解。
Target:描述了注解修饰的对象范围,取值在java.lang.annotation.ElementType定义,常用的包括:
METHOD:用于描述方法
PACKAGE:用于描述包
PARAMETER:用于描述方法变量
TYPE:用于描述类、接口或enum类型
Retention:表示注解保留时间长短
SOURCE:在源文件中有效,编译过程中会被忽略
CLASS:随源文件一起编译在class文件中,运行时忽略
RUNTIME:在运行时有效
常用在登陆验证、打印日志等。
6.tree set 如何去重
tree set是使用compareTo来进行排序和去重的.比较的是自己的某个属性与对象属性的差值,如果返回的是0,则说明重复。如果是正数则往后面排,如果是负数则往前面排。可以通过实现compareable接口来进行对compareTo方法的重写,定义排序及去重规则。
补充:hashSet去重原理。
比较hashcode 然后再通过equals比较。也可以通过改变这两个来实现自定义。
7.arraylist与linklist的区别
ArrayList是数组,是一块连续的内存空间。
LinkList 是双向链表,不是一块连续的内存空间。
ArrayList因为是一块连续的内存空间,所以查找快,方便寻址。但是插入、删除慢,因为需要发生数据迁移。
LinkList查找慢,因为需要通过指针一个一个的进行查找。但是插入、删除快,
因为只需要改变前后节点的指针指向即可。
这只是比较笼统的概念
插入删除跟查找也是要分情况的,比如插入、删除在中间部分或者在末尾部分。查找第几个元素或者某个元素在什么位置不同的情况也是不一样的。
补充:arraryList的扩容机制,本身的默认值是10,在添加第11个元素时时会进行位运算扩容到1.5倍。
linklist的每一个对象中会存储三个空间,两个存储指针指向前后,一个存储对象。
8.序列化和反序列化的作用
序列化就是把对象转换成字节序列的过程。
反序列化就是把字节序列恢复成对象的过程。
序列化就例如我们要把Java对象存储到硬盘上或者传送给网络上的其他计算机,我们需要调用outputstream的writeobject方法来将Java对象转换成某个格式的字节流,但是要求必须实现serializable接口,这样在编译的时候才会进行特殊处理,该接口没有需要实现的方法只是作为对象可被序列化的标注。
Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。
反序列化调用的方法是inputstream的readobject。都在java.io.object下。
9.Spring如何创建对象及生命周期
暂无
10.mysql隔离级别
为了解决并发的情况下,数据的安全性问题。
Read_Uncomited(脏读):读取过期的数据,就是一个事物读到另一个事务未提交的新数据,最低隔离级别,一切皆有可能;
Read_Commited(幻读):读取临时的数据,就是一个事物在进行修改全表的时候,另一个事务对数据进行了新增,从而第一个事务的执行完后发现还有没有修改的数据,就好像发生了幻觉一样;
RepeaTable_Read(不可重复读):就是在同一个事务中先后执行两条一样的select语句,之间没有执行过Del 语句但先后结果不一样,这就是不可重复读;;
Serializable:串行化,最高隔离界别,杜绝一切隐患,但效率较低;
知乎:
READ UNCOMMITTED 读未提交,脏读、不可重复读、幻读有可能发生。READ COMMITTED 读已提交,可避免脏读的发生,但不可重复读、幻读有可能发生。
REPEATABLE READ 可重复读,可避免脏读、不可重复读的发生,但幻读有可能发生。
SERIALIZABLE 串行化,可避免脏读、不可重复读、幻读的发生,但性能会影响比较大。
脏读:未提交但是就可以读到数据了,就会导致数据出现一些错误的计算。
不可重复读:同一事务执行的比较长,然后期间提交了两次数据,那么这个事务中就会出现两次不一样的数据。或者就是在同一个事务中先后执行两条一样的select语句,之间没有执行过Del 语句但先后结果不一样,这就是不可重复读。
幻读:在一个事务修改表的时候,另一个事务对表进行了增加。但是第一个事务执行完成后发现有一些数据没有进行修改,这就是幻读。