关于面试题的一些思考
1.前端部分
1.1.关于Vue的父子组件值传参?
父传子:可以让父组件绑定子组件,然后子组件用props来接受父组件的参数
子传父:可用this.$emit来传递子组件的内容,父组件直接在methods中引用
父:用ref属性配合&refs.refname.方法名主动获取子组件内容
子:利用this.$parent来处理,等于获取到父组件的this
1.2.Vue的生命周期
1.创建Vue实例
2.beforeCreate:初始化生命周期和组件,用的少
3.create:创建完成data和methods,通常用于获取列表数据发起axios请求
4.beforeMount:create之后会开始解析<template>模板,这个钩子暂时还不无法获取到真实的DOM元素
5.Mounted:Vue的元素UI已经渲染完,可以用mounted来操作真实元素
6.beforeUpdate: 正要执行更新DOM元素更新操作
7.Update:已经更新完成DOM元素
8.beforeDestroy:准备销毁组件
9.destroyed:生命周期结束,组件销毁
1.3.什么是Vuex?
是关于Vue的状态管理,方便与兄弟组件进行通讯
核心内容是state(具体状态)、getter(对外的获取状态)、mutation(更改状态的值)、action(提交mutation)、module(对更多的状态进行分组划分)
2.后端部分(Java)
2.1.基础部分
2.1.1.什么是原子操作
不会被打断的操作
2.1.2.关于volatile是什么?怎么用?
可以用在多线程环境中保证变量的可见性和有序性,但是不适用于复合性场景如i++等,比较适用于 布尔标记,触发器。
2.1.3.什么是不可变对象?他们对并发应用有什么帮助?
不可变对象类似于String、或者基本类型的包装类,他们的常量是在构造函数中创建的、他们是线程安全的
2.1.4.简述JVM模型、且用来存放什么数据?
方法区:用来放常量和static对象
堆:new出来的实例对象
栈:方法执行、和地址引用
本地方法栈:为Native方法服务(非Java提供的实现方法)
程序计数器:记录当前线程的执行行号
2.1.5.几种常用的调试内存的工具?
栈:jstack
内存:jmap
dump堆信息:jhat
2.1.6.GC如何判断对象存活?
1.引用计数法:判断对象是否有被引用、如果引用计数器为0,则判断为死对象
2.可达性算法:通过GCRoots 向下索引引用链,如果没有引用链相连则不可用
2.1.7.关于垃圾回收机制的理解
垃圾回收机制是Java中一个在持续运行优先级比较低的线程、只有在线程空闲的时候才会进行扫描回收没有被任何引用的对象。
2.1.8.Java中垃圾回收的方法
标记清除法:通过标记进行统一回收和清除(问题是效率低、会产生不连续内存碎片)
复制算法:划分两个相等的内存,将第一个内存中存活的对象直接复制到第二个内存中,然后直接销毁第一个内存空间
2.1.9.关于类加载器
启动类加载器:加载Java核心库无法直接引用
扩展类加载器:用来加载Java的扩展库
系统类加载器:可以根据Java应用路径来加载Java类
用户自定义加载器: 通过继承类加载器来实现具体方法
2.1.10.BIO、NIO、AIO的区别简述
BIO是一个连接一个线程
NIO是一个请求一个线程,客户端发送的请求会注册到多路复用器上,多路复用器轮询到有I/O请求的时候才会创建线程
AIO是一个有效请求一个线程
2.1.11.NIO的组成
buffer:与channel进行交互(缓冲区的数据读写)
flip:反转缓冲区,用来切换读写模式
clear:清除缓冲区
rewind:重绕缓冲区将position重置为0
DirectByteBuffer:减少一次系统空间到用户空间的拷贝
Channel:IO源与目标源的通道,双向的只能与Buffer进行交互
Selector:用一个单独的线程管理多个Channel,可监听读、写、连接、accept
2.1.12.NIO如何通过Buffer来缓冲数据?
写入数据到Buffer,调用flip()方法,从Buffer中读取数据,调用clear()方法或者compact()方法。
capacity: 缓冲区容量的大小,就是里面包含的数据大小。
limit: 对buffer缓冲区使用的一个限制,从这个index开始就不能读取数据了。
position: 代表着数组中可以开始读写的index, 不能大于limit。
mark: 是类似路标的东西,在某个position的时候,设置一下mark,
2.1.13.什么是NIO?
NIO是一个非阻塞IO,基于Reactor模型实现。可以理解成由一个线程来处理大量的连接请求,通过一个线程轮询大量channel,每次获取到有事件的channel就启动一个线程来处理,核心就是非阻塞。selector线程不停的轮询channel,所有客户端请求都不会阻塞,无非就是需要排队等待。
2.1.14.为什么说NIO是同步非阻塞?
因为无论多少客户端都可以接入服务端,客户端接入并不会耗费一个线程,只会创建一个连接然后注册到selector上去罢了,你就可以去干其他你想干的其他事情了, 一个selector线程不断的轮询所有的socket连接,发现有事件了就通知你,然后你就启动一个线程处理一个请求即可,这个过程的话就是非阻塞的。但是这个处理的过程中,你还是要先读取数据,处理,再返回的,这是个同步的过程。
2.1.15.多路复用机制是如何支持海量连接的?
对Socket发起的连接不需要每个都创建一个线程,完全可以使用一个Selector来多路复用监听N多个Channel是否有请求,该请求是对应的连接请求,还是发送数据的请求,这里面是基于操作系统底层的Select通知机制的,一个Selector不断的轮询多个Channel,这样避免了创建多个线程,只有当莫个Channel有对应的请求的时候才会创建线程,可能说1000个请求, 只有100个请求是有数据交互的, 这个时候可能server端就提供10个线程就能够处理这些请求。这样的话就可以避免了创建大量的线程
2.1.16.NIO服务的建立过程?
1.先打开一个Selector:selector.open()
2.创建服务端的channel
3.绑定到某个端口上,并进行相关配置
4.注册到selector上
5.轮询拿到已经就绪的事件
2.1.17.关于线程池的执行原理?
1.会先判断核心线程是否满,如果未满则安排线程执行task任务
2.如果核心线程已满,则判断线程阻塞队列是否已满,未满则进入阻塞队列
3.如果阻塞队列已满,则判断是否大于最大核心线程数,没大于则创建线程执行task任务
4.如果已经是最大核心线程数,那么则会执行淘汰策略淘汰无法执行的task任务
2.1.18.Executors的四种线程池?
1.newSingleThreadPool():单一线程池
2.newFixedThreadPool():固定线程池
3.newCacheThreadPool():缓存线程池- 有task任务进来创建线程缓存60s,60s后无调用则销毁
4.newScheduledThreadPool():周期线程池-创建具有周期性和支持定时的线程
2.1.19.HashMap为什么采用红黑树,而不是AVL树?
AVL树是高度平衡树,在新增删除后可能需要多次旋转来平衡
红黑树则是弱平衡树,红黑树丛根到叶子最长路径不会超过最短路径2倍,旋转次数比较少在插入删除操作的时候
2.1.20.什么是CAS?应用场景?
CAS:比较并交换
核心是存在三个值 V(内存地址) A(预期值) B(更新值)
当V与A相等时,再更新B
应用场景:ConcurrentHashMap、数据库CAS+乐观锁
缺点:
ABA问题:V与A相等但实际上V可能已经变化好几次了,CAS看不见
解决方案:版本机制
自旋周期过长
2.1.21.了解过Stream流吗?常用的几个方法?
foreach 遍历、map 转换映射对象、 collection将处理结果变成集合对象
max、min求集合中最大值最小值,要有比较器接口(类似Integer这些)
count 返回元素个数
distinct:去重
filter:根据条件过滤
sorted:排序