自我介绍
java集合、hashmap详细介绍、关键参数、线程安全的集合、队列和栈、用两个栈实现队列算法
jvm结构
JVM包含两个子系统和两个组件
两个子系统为类装载和执行引擎
两个组件为运行时数据区和本地接口
类装载:根据给定的全限定类名,来装载class文件到运行时数据区的方法区中
执行引擎:执行类中的指令
本地接口:与本地库交互,是其他编程语言交互的接口
运行时数据区:这个就是我们常说的jvm内存
运行时数据区
方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据
本地方法栈:如果当前线程执行的方法是native类型的,这些方法就是再本地方法栈执行的
虚拟机栈:用于存储局部变量表、操作数栈、动态链接、方法出口等信息,也就是说,虚拟机栈是一个线程执行的区域,调用一个方法,就会向栈中压入一个栈帧;一个方法执行完,就会弹栈
堆:java对象实例在堆中分配,被所有线程共享,当堆无法满足内存分配需求时,将抛出oom(Out Of Memory)异常
程序计数器:当前线程所执行的字节码的行号指示器,字节码解析器是通过改变这个计数器的值,来选取下一条需要执行的字节码指令; 分支、循环、跳转等都需要依赖这个计数器来完成
jvm垃圾回收算法
标记-清除算法:
标记无用对象,然后进行清除回收。
优点:实现简单,不需要对象进行移动
缺点:标记清楚效率低,产生大量不连续的内存碎片,提高了垃圾回收的频率
复制算法:
为了解决标记-清除算法效率低的问题,产生了复制算法,他把内存空间分为两块相同的区域,每次只使用其中的一块区域;垃圾收集时,遍历当前区域,把存活的对象复制到另一块区域,最后将当前区域可回收的对象进行回收。
优点:按照顺序分配内存即可,运行效率高,不用考虑内存碎片
缺点:可用的内存空间变成了原来的一半
标记-整理算法:
在新生代中可以使用复制算法,但是在老年代中,就不能了,因为老年代对象的存活率较高,这样就会有较多的复制操作,导致效率变低,标记-清楚算法可以应用在老年代中,但是他的效率不高,在内存回收后,容易产生大量的内存碎片。
因此,就出现了标记-整理算法,在标记可回收的对象之后,将所有存活的对象压缩到内存的一端,使他们紧凑的排列在一起,然后对这端以外的内存进行回收,回收后,已使用和为使用的内存都各占一端。
优点:解决了标记-清楚算法内存碎片化问题
缺点:仍然需要局部对象移动,效率不高
分代收集算法:
当前商业的虚拟机,都采用了分代收集的垃圾回收算法
将对象的存活周期分为几块,分别是:年轻代、老年代和永久代
默认情况下,年轻代占比三分之一,老年代和永久代占比三分之二
新生代使用的是复制算法,老年代使用的是标记-整理算法
新生代的复制算法,默认8:1:1
分别有 Eden、To Survivor和From Survivor
每次复制的时候,将Eden + From Survivor 存活的对象放入To Survivor,
情况Eden + From Survivor区域,下一次将Eden + To Survivor存活的对象放入From Survivor
每次从From Survivor移动到To Survivor都存活的对象,年龄+1,当年龄到达15(默认15)的时候,升级为老年代。
有一些大的对象,也会直接存入老年代
老年代的内存占比到达某个值时候,会触发全局垃圾回收,一般使用标记整理的垃圾回收算法。
多线程锁:synchronized、reentrantlock、countdownlatch、锁升级
mysql隔离级别
隔离级别
READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。oracle的默认隔离级别
REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。 mysql的默认隔离级别
SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
什么是脏读?幻读?不可重复读?
脏读(Drity Read):读取到了其他事务未提交的数据,未提交可以回滚,说明读取到了并非存在的数据
不可重复读(Non-repeatable read):在一个事务内,两次读取到的数据不一致,原因是其他事务做了更新操作并提交导致的
幻读(Phantom Read): 事务两次查询得到的不同的结果集,侧重的方面是所查询出的数据状态无法支撑后续的业务操作
不可重复读侧重表达 读-读,幻读则是说 读-写,用写来证实读的是鬼影
线程池有哪些、核心参数、线程池运行机制
线程池有哪些
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
线程池的参数
1.corePoolSize:核心线程数,也就是正常情况下创建工作的线程数,这些线程创建后并不会消除,而是一种常驻线程。
2.queueCapacity:任务队列容量(阻塞队列)
3.maxPoolSize:最大线程数
4.keepAliveTime:线程空闲时间
5.allowCoreThreadTimeout:允许核心线程超时
6.rejectedExecutionHandler:任务拒绝处理器
线程池的运行机制
当线程运行的时候,如果没有设置成预启动加载,线程数是0;
当提交一个新任务的时候,他会建立一个核心线程数去执行,此时如果一直来任务,之前的也没有执行完,他会一直创建核心线程;
当到达核心线程数时,如果大家都在忙,那么会放到阻塞队列中;
如果阻塞队列也放满了,而且核心线程还在忙,那就会去建立非核心线程,如果一直创建,数量达到非核心线程的最大数,就会触发一个拒绝策略。
JDK内置了四种拒绝策略:
AbortPolicy直接抛异常
DiscarePolicy悄无声息的丢弃任务
DiscardOldestPolicy丢弃你最早未执行的任务
CallerRunsPolicy谁调用返回谁执行,这种方式会影响新任务的提交速度
Threadlocal
ThreadLocal是线程独有的实例,适用于每个线程需要自己独立的实例,但是需要在多个方法中被使用。
也就是说,变量在线程间隔离,在方法或类间共享
使用场景:
1、存储用户Session
2、数据库连接,处理数据库事务
3、ThreadLocal 保存一些业务内容(用户权限信息、从用户系统获取到的用户名、用户ID 等),这些信息在同一个线程内相同,但是不同的线程使用的业务内容是不相同的
4、Spring使用ThreadLocal解决线程安全问题
写线程安全单例模式,volatile原理
线程安全的单例模式
private static Singleton instance;
//线程安全 加锁
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
private static volatile Singleton instance;
//双重检查方式 这种方式 需要加volatile关键字
public static Singleton getInstance() {
//第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实际
if(instance == null) {
synchronized (Singleton.class) {
//抢到锁之后再次判断是否为空
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
可见性、有序性、原子性
原子性:原子性是指一个操作cpu中不可以中途暂停然后再调度,要不全部执行完成,要不都不执行
可见性:当多个线程访问同一变量时,一个线程修改了这个变量的值,其他线程马上可以看到修改的值
有序性:虚拟机在进行代码编译时,对于那些改变顺序之后不会对最终结果造成影响的代码,虚拟机不一定按照我们的顺序来执行,有可能将他们重排序。
对于有些代码重排序之后,虽然对变量的值没有造成影响,但是可能会出现线程安全问题
volatile原理
volatile解决了指令重排问题,保证了可见性和有序性,但是无法解决原子性
volatile作用
保证多线程下的可见性
禁止进行指令重排序(即保证有序性)
volatile只能保证对单次读/写的原子性,i++ 这种操作不能保证原子性。
如何解决的?
java程序执行时,会编译成字节码,通过加载器加载到jvm中,jvm执行字节码,最终将其转变为汇编代码相关的cpu指令,对于被volatile修饰的变量将其转变为汇编指令后,比普通的变量多一行lock为前缀的指令
解决可见性
当对volatile变量执行写操作后,JMM(Java Memory Model,即JMM)会把工作内存中的最新变量值强制刷新到主内存,写操作会导致其他线程中的缓存无效
这样,其他线程使用缓存时,发现本地工作内存中此变量无效,便从主内存中获取,这样获取到的变量便是最新的值,实现了线程的可见性
解决有序性
JVM的实现会在volatile读写前后均加上内存屏障,在一定程度上保证有序性
写单词拆分问题
10.反问
好像叫基础平台部门。java岗。
总体来说,快手的一二面会根据难度循序渐进,并且会出一两个由易到难的算法题。一面偏向基础,二面偏向项目去问。
一面:
synchronized用法
类加载
什么是类加载
jvm把class文件加载到内存中,并对数据进行校验、解析和初始化,最终形成可以被虚拟机直接使用的java类型文件
jvm加载class文件原理机制
java中的所有类,都需要类加载器装载到jvm中才能运行。
类加载器本身也是一个类,他的工作就是把class文件从硬盘读取到内存中。在写程序的时候,我们不需要类的装载,因为他都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显式的加载所需要的类。
隐式装载:程序运行过程中,通过new方式生成对象,隐式调用类装载器加载对应的类到jvm中
显式装载:通过class.forname()等方法,显式加载所需要的类
java类的加载是动态的,他并不会一次性加载所有的类到内存中,而是保证程序运行的基础类(基类)完全加载到jvm中;至于其他类,则在需要的时候才加载
类加载器有哪些
启动类加载器(Bootstrap ClassLoader)加载java的核心类库,无法被java程序直接引用
扩展类加载器(extensions class loader)加载java扩展库,java虚拟机的实现会提供一个扩展类库目录,该类加载器在此目录里面查找并加载java类
系统类加载器(system class loader)他根据java的类路径(class path)来加载,一般来说,java应用的类都是由他加载的,可以通过ClassLoader.getSystemClassLoader()来获取它
用户自定义类加载器,通过继承java.lang.classloader类的方式实现
类装载的执行过程
根据路径找到文件 -> 检查文件正确性 -> 给静态文件分配内存空间 -> 将符号引用转为直接引用 -> 对静态变量和静态代码块执行初始化操作
双亲委派模型
一个类收到加载请求,它会先去找父类是否加载,只有父类无法加载或者加载完成时,子类才去加载
spring的循环依赖如何解决
群发红包如何设计
public、protect、default、private
static修饰 作用域
java基础类型
忘了。。
算法题:
合并链表
思路:创建一个实体类ListNode,两个参数,一个当前值,一个链表的指向;
遍历链表比较大小,,list1>list2、list1<list2、遍历完成后,将另一条指向该条链表的后面
public class NodeListDemo {
public static void main(String[] args) {
/**
* 1->2->3->4->10->
* 6->7->8->9->
*
* 处理完成后:
* 1->2->3->6->7->8->9->10->
*/
//新建链表1
ListNode listNode = new ListNode(1);
listNode.next = new ListNode(2);
listNode.next.next = new ListNode(3);
listNode.next.next.next = new ListNode(4);
listNode.next.next.next.next = new ListNode(10);
//打印链表
printNode(listNode);
//新建链表2
ListNode listNode2 = new ListNode(6);
listNode2.next = new ListNode(7);
listNode2.next.next = new ListNode(8);
listNode2.next.next.next = new ListNode(9);
//打印链表
printNode(listNode2);
//合并链表
ListNode nodeList = mergeListNode(listNode,listNode2);
//打印链表
printNode(nodeList);
}
/**
* 合并链表
* @param listNode1
* @param listNode2
* @return
*/
private static ListNode mergeListNode(ListNode listNode1, ListNode listNode2) {
//创建一个新链表
ListNode list=new ListNode(-1);
//合并的链表
ListNode mergeNode = list;
//如果有一方为空,说明遍历完成
while (listNode1 != null && listNode2 != null){
//两种情况
if (listNode1.val <= listNode2.val){
mergeNode.next = listNode1;
listNode1 = listNode1.next;
}else {
mergeNode.next = listNode2;
listNode2 = listNode2.next;
}
//指向完成,当前链表向后移动
mergeNode = mergeNode.next;
}
//如果一个链表遍历完成 另一个链表直接连到后面
if (listNode1 == null){
mergeNode.next = listNode2;
}else {
mergeNode.next = listNode1;
}
return list.next;
}
/**
* 打印链表
* @param listNode
*/
private static void printNode(ListNode listNode) {
//当前节点 遍历使用
ListNode tempNode = new ListNode();
tempNode = listNode;
while (tempNode != null){
System.out.print(tempNode.val + "->");
tempNode = tempNode.next;
}
System.out.println();
System.out.println("---------");
}
//声明链表实体
static class ListNode{
int val;
ListNode next;
public ListNode() {
}
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
}
字符串合并相邻的相同字符
/**
* 将字符串中相邻相同的子串合并为一个子串,如"12342343454565678789" -- "123456789"
*/
public class MergeStringDemo {
public static void main(String[] args) {
String result = "";
String temp1 = "12342343454565678789";
for (int i = 0; i < temp1.length(); i++) {
char c = temp1.charAt(i);
if (result.indexOf(c) == -1){
result = result.concat(String.valueOf(c));
}
}
System.out.println(result);
}
}
二叉树的深度(手写算法)
/**
* 求二叉树的深度
*/
public class TreeDepth {
public static void main(String[] args) {
Node node = new Node();
Node node1 = new Node();
Node node2 = new Node();
Node node3 = new Node();
Node node4 = new Node();
Node node5 = new Node();
Node node6 = new Node();
Node node7 = new Node();
node.left = node1;
node.right = node2;
node1.left = node3;
node1.right = node4;
node3.left = node5;
node2.right = node6;
node5.left = node7;
int depth = getTreeDepth(node);
System.out.println(depth);
}
private static int getTreeDepth(Node node) {
if (node != null){
int left = getTreeDepth(node.left);
int right = getTreeDepth(node.left);
return left > right ? left+1:right+1;
}
return 0;
}
}
class Node{
Node left;
Node right;
}
二面:
实习经历
项目
以下为RabbitMQ问题:
RabbitMQ基础概念
限流消峰
架构
生产者 broker端 消费者
有哪些机制保证消息传输正确性
一条消息分为三个阶段
生产阶段、存储阶段、消费阶段
生产阶段
生产者生产消息发送给mq(broker端),mq(broker端)收到消息后,会返回给客户端一个确认信息,表示消息已经收到
消息确认机制中需要明确
同步发送:即要处理好返回值,又要处理好对异常的捕获
异步发送:处理好回调方法
超时重试机制:如果长时间收不到确认返回结果,则需要进行重试,直到消息发送成功,或者在重试一定次数后发送报警,人工参与
存储阶段
存储阶段指的是broker端,一般情况,只要broker端不宕机,都是没有什么问题的
但是如果宕机了,是会发生消息丢失的情况的,例如:kafka为了性能,只要消息写入pageCache就会返回确定消息,消息提交后,如果还没有刷盘就发生宕机,就会存在消息丢失的风险
对于单个节点的broker,需要配置相关的参数,在收到消息后,将消息写入磁盘后,再给producer返回确认响应
例如RabbitMQ,将消息的delivermode设置为2,exchange持久化后才返回确认消息,保证消息不会丢失
RocketMQ将flushDiskType设置为SYNC_FLUSH同步刷盘机制,就不会出现消息丢失
如果是多节点集群,会将Broker集群配置成至少将消息接收到一定的阈值后,才给producer返回确认信息(例如 N/2+1 )
消费阶段
消费阶段采用和生产阶段类似的确认机制来保证消息的可靠传递,客户端从broker端拉取一条消息后,执行消费逻辑,执行完成后,会返回给broker端确认响应,如果broker端没有收到确认响应,下一次拉取还会是同一条消息,来确保消息不会在网络传输中丢失,也不会因为客户端在执行消费逻辑中出错导致丢失。
多个消费者消费相同分区的注意点
如果同一消费组内,消费者A消费了index=10这条消息,还没有返回确认,这时这个分区的消费位置还是10,此时,如果消费者B来拉取消息,就会出现两种情况
超时前:Broker认为这个分区还被A占用,拒绝B的消费请求
超时后:Broker认为A超时还没有返回确认响应,这次消费就失败了,当前消费位置还是10,B再来拉取消息,消费的还是index = 10
重试消费失败场景
对于一直无法消费的消息,超时一定次数后,会将消息写入死信队列,避免分区被卡住
消息队列如何处理重复消息
如果消息在网络传输中出现错误,由于发送发接收不到确认,就会一直通过重新发送来避免消息不丢失。但是,如果确认响应在网络传输中丢失,也会导致重新发送,所以在我们编写消费代码时,就需要考虑这种情况,在消费时,怎样才会避免这种情况
一般有几种解决方式
建立消息消费表,拿到消息后,向消费表插入一条数据,使用消息id作为主键id,当重复消费的时候,会出现主键冲突
利用redis给消息分配一个全局id,只要消费过该消息,将消息以K-V形式存入redis,消息消费的时候,会根据key去redis查询是否有对应的记录
以采用布隆过滤器或者bitmap方式实现,类似第二种情况
如果数据量过大,我们可以采用hash方式将id分散到上万个队列中去,这样一个key值也就存储几万个数据,不会很大;如果是数据库,可以分库分表
事物下,假设最后一个commit操作丢失了,此时怎么办
算法题:
归并排序
牛客:
求集合的所有子集
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 思路:
*
*
* // 6 5 4 3
* // 65 6 5 65
* // 654 4 64 54 654
* // 6543 3 63 53 653 43 643 543 6543
*
*
* 65 分为 6 5 65
* 654 分为 6 5 65 4 64 54 654
* 6543 分为 6 5 65 4 64 54 654 3 63 53 653 43 643 543 6543
*
* 总结:每次抛出最后一个数字,然后最后一个数字和前面的所有数字进行配对
*
*
*/
public class MergeSort {
public static void main(String[] args) {
//int[] ints = new int[]{6,5,4,3,2,1};
int[] ints = new int[]{6,5,4};
for (int anInt : ints) {
System.out.print(anInt+"-");
}
System.out.println("----");
List<List<Integer>> list = new ArrayList<>();
//构建子集
bulidSubSet1(ints,list);
System.out.println(list);
}
private static void bulidSubSet1(int[] ints, List<List<Integer>> list) {
if (ints.length == 1){
list.add(Arrays.asList(ints[0]));
}else if (ints.length > 1){
//递归求 n-1 个非空子集
bulidSubSet1(Arrays.copyOf(ints,ints.length-1),list);
//此时list里面有几条数据,那么就需要便利几次
int size = list.size();
//将最后一个数字添加到集合中 例如 65 第一次循环添加的就是5 654 递归循环第一次添加的是5,第二次是4
list.add(Arrays.asList(ints[ints.length-1]));
//下面的逻辑是 将抛出的数和前面的数据结合,组成新的数组添加到集合中
List<Integer> clone;
for (int i = 0; i < size; i++) {
clone = new ArrayList<>();
for (Integer integer : list.get(i)) {
clone.add(integer);
}
clone.add(ints[ints.length-1]);
list.add(clone);
}
}
}
}
自我介绍,不问项目直接开怼java
java八大数据类型是啥,各自占多少单位,float 能表示0.25吗 int 的数据范围是多少
一个字节是八位, float可以表示0.25,int的数据范围是 -2^31到2^31-1
java list接口拿啥实现的,ArrayList和LinkedList 删除一个元素的时间复杂各是多少
list接口实现了Collection,
ArrayList底层是数组实现,删除或者插入元素的时候,都需要做一次元素的复制
ArrayList实现了RandomAccess接口,所以查找的时候非常快
所以比较适合顺序添加,随机访问的场景
删除一个元素时间复杂度为:
LinkedList底层是双向链表结构,所以插入或者删除非首尾数据的操作时,效率较快;查询的时候需要从前往后依次查找,所以查询慢
内存占用情况:LinkedList比ArrayList更加占用内存,因为LinkedList的节点,除了存储数据,还要存储引用,一个指向前一个节点,一个指向后一个节点
综合来说:一般需要查询多增删少的情况,优先使用ArrayList,查询少,增删多的使用LinkedList;
hashmap的put的时候啥过程,扩容的时候啥样,怎么判断元素是低位还是高位
利用key的hashcode计算出下表,存储到map中,如果出现key相同,覆盖原始值;如果key不同,则将当前的key-value放入链表中
取值时,直接找到hash值的下标,再进一步判断key值是否相同。
jdk1.8对HashMap的实现做了优化,当链表中的节点超过阈值(默认为8)个之后,该链表会转换成红黑树来提高查询效率,从原来的O(n)到O(logn);插入的方式从头插法变为尾插法
当数组的实际大小,大于其临界值(第一次为12,16的0.75),会进行扩容
ConcurrentHashMap 底层具体实现知道吗?实现原理是什么?
ConcurrentHashMap 相当于一个加了锁的HahsMap
HashTable和ConcurrentHashMap对比‘
HashTable全表锁,直接锁住put方法
ConcurrentHashMap采用了分段锁的思想,jdk1.7对整个桶数组进行了分段切割,每一把锁只锁容器一部分(默认分配16个Segment,效率是HashTable的16倍)
1.8后,摒弃了分段锁思想,而是使用Node数组的思想(一个链表锁一个,只要不hash冲突,就不会产生并发,效率提升了N倍),并发控制使用synchronized和CAS(如果相应的位置还没有加锁,则调用CAS插入相应的数据)来操作。
CAS原理
CAS(Compare and Swap):比较并交换。通过利用底层硬件平台的特性,实现原子性操作
例如:并发情况下,将A修改为C的时候,判断当前是否为A,如果是,才修改
java里面线程怎么通信的,锁,说说synchronize的锁升级过程,说到monitor
sleep方法让线程陷入休眠状态,时间到达后醒来
wait方法让线程陷入阻塞状态,通过notify方法唤醒
Thread.join()的使用
join是插队的意思,调用join的线程应该立刻的到CPU的运行时间
例如:主线程需要等到子线程执行完成之后,拿到结果,这时候需要用到join方法
synchronize的锁升级过程
偏向锁:只有一个线程争抢锁资源的时候,将线程拥有者标记为当前线程
轻量级锁(自旋锁):一个或者多个线程通过CAS去争抢锁,如果抢不到则一直自旋
重量级锁:多个线程争抢锁,向内核申请锁资源,将为争抢成功的锁放到队列中直接阻塞
为什么要有锁升级过程
6 知道有哪些排序算法,平均时间复杂度是多少
7 redis的zset怎么实现的,那么跳跃表的原理是啥,zscore用过吗,时间复杂度是多少
8 输入url发生了什么,ip找mac地址是啥协议
9 用的web容器是啥,url请求咋传到tomcat然后再咋到controller的
10 这个requestmapping 的map啥时候初始化的
11 写代码:单链表的归并排序
12 单例模式懒汉
13 单例模式饿汉
14 单例模式双重锁检查 volatile有啥作用(防止指令重排序)
15 内部类的单例模式写法
16 智力题:两人抛硬币,我先抛,谁先扔出来正面,谁赢,问我赢得概率是多少
1.自我介绍
2.项目介绍
3.如何判断一个用户是否在线?
4.怎么做的权限检验?(其他人对你消息进行抓包)
5.有没有学过token?
6.netty怎么实现的聊天?
7.连接管理怎么实现的?怎么判断这个用户断开?
8.考虑过怎么给这个项目植入漂浮广告吗?
9.连接断开是客户端断开还是服务端?
10.为什么选择netty,为什么不直接使用TCP?那个的性能更加好?
11.简述AQS
12.volatile与synchronized的区别?
13.synchronized与Lock的区别?
14.如何对一个代码块选择合适的同步机制?
15.有没有学习过服务降级?
16.spring的链路过程?
17.spring的AOP
18.简述代理模式?
19.动态代理和静态代理?
20.mysql的MVCC是什么?
21.数据库的隔离级别都有那些(MySQL是那个)?
22.怎么解决幻读?
23.MySQL的索引都有那些?
24.B树与B+树的区别?
24.范围查找选择那个数据结构比较好?
25.redis的数据结构都有那些?
堆排序?
二叉树的层序遍历
快手java一面
1.自我介绍
2.聊项目
3.java基本数据类型,long几位, 能存储什么范围的数据 ,float怎么存储小数的
4.String是基本数据类型吗 底层怎么实现的 (final修饰的char数组)
5.volatile关键字底层,如何实现可见行和有序性,为什么不能保证原子性
6.synchronized关键字底层,静态方法锁的是什么,非静态方法锁的是什么,静态代码块锁的是什么
7.hashmap put元素的原理,1.8以后的优化有什么,为什么长度超过8变成红黑树
8.数据库得事务隔离级别,innodb的默认隔离级别
9.innodb有哪些索引,聚簇索引与非聚簇索引区别,覆盖索引怎么实现
10.联合索引的失效情况,给了个例子
11.mvcc机制的原理
12.数据库乐观锁和悲观锁
13.b+树与b树,为什么用b+树
14.redis五种基本数据类型,sortedset底层是怎么实现的
15.缓存穿透,缓存击穿,缓存雪崩,分别怎么解决
16.一个排序二叉树,一个target值,寻找二叉树中的比target值小的最大值
17.上一题不会,换成大数相加了(我这个垃圾)
18.概率题:两个人抛硬币,抛到正面赢,先抛的人赢的概率(2/3)
cpu占用100%,如何排查问题(考Linux命令吗?)
快手一面
数据库update过程
怎么解决幻读
treemap和linkedhashmap
wait和sleep方法区别
线程池相关(工作队列、核心线程最大新任务什么状态、线程存在哪(没听懂
synchronized原理
volatile
撕 单链表两两反转
之前发过一次一面面经,这次和二面的一起发了
自我介绍
二话不说,先写一个LRU,吭哧吭哧写了二十多分钟,之后面试官给提了一些优化意见。
TreeSet 和 HashSet 是怎么比较元素是否相等的?
Integer 和 Long 的 hashCode() 方法实现有什么区别?
ConcurrentHashMap 原理,1.7 和 1.8 区别。
线程池有哪些参数,执行流程是怎样的?有哪些常用 BlockingQueue,区别是什么?拒绝策略有哪些?shutdown() 和 shutdownNow() 有什么区别?
synchronized 和 ReentrantLock 区别?ReentrantLock 实现原理,AQS 原理,CountdownLatch 和 Semophore 的作用?
ThreadLocal 原理,线程池中使用 ThreadLocal 会有什么问题,为什么?软引用和弱引用有什么区别?
单例模式有哪些实现方式?双重检查锁怎么实现,为什么用 volatile,序列化破坏单例了解吗,怎么避免?
聚簇索引和非聚簇索引区别,sql 语句执行有哪些步骤?
事务隔离级别有哪些?可重复读怎么解决幻读?binlog 有什么作用?
MySQL 存储时间有哪些数据结构?有什么区别?
Redis 想要提交多条命令,但是只有一次 Round-Trip 怎么实现?pipeline 了解吗?持久化方式有哪些,区别是啥?AOF 重写介绍一下,fork 子进程有什么影响?
竟然没有反问环节,有点慌…
二面 55min
自我介绍。
final 关键字的用法。
在哪些情况下,变量虽然没有使用 final 显式修饰,但还是被编译器提示不可修改?
谈谈你对 SpringBoot 的理解,主要解决了哪些问题,集成了那些第三方框架?支持哪些数据源?
说一下进程和线程的区别?Java 里的进程和线程是怎么体现的?
基础知识先聊到这里,下面来写个代码:有一张桌子,桌子上有一摞一摞的盘子,每摞盘子的数量是已知的,数量是无序且不等的,现在需要你去挪盘子,通过尽量少的挪动次数,使每个位置上的盘子数量趋于平均,需要你打印出每一次挪动盘子的动作,比如从位置 a 挪到位置 b (a和b是数组的下标),那就打印 a->b。输入是一个无序数组,输出是每一次挪动盘子的过程。这道题写了挺久,加上跟面试官讨论的时间都半个多小时了。
代码先写到这里,我们在聊些别的问题,关于 Java 并发编程,你都了解哪些方面?
Java 最经典的 synchronized 关键字,你了解它的用法吗?
同步代码块中怎么释放锁?Object.wait() 的底层原理是什么?或者说 wait() 和 notify() 的机制在底层是怎么实现的?
JUC 包下常用的锁有哪些?ReentrantLock 中有个 Condition ,你了解吗,一般怎么使用?
你在实际项目中有没有用过 MySQL 的一些高级功能,比如事务之类的,使用场景是什么?
使用场景这个记得不太清楚了,答得磕磕巴巴,然后面试官说你没实际用过的话就不用说了…
你简单介绍一下 MySQL 的隔离级别吧。
反问环节。
55min
1. object类有哪些方法
2. clone方法的使用
3. 隔离级别
完全二叉树和满二叉树
相关知识点: 树dfs
相关知识点: 树dfs
相关知识点: 树dfs
相关知识点: 树dfs
5. 接口里面常量的特点,1.8之后
6. redis数据类型
7. 设计模式,享元模式内容
8. 线程池参数,大小设置
9. 索引的类型,myisam的优点
10. redis分布式锁的实现
11.分布式锁实现的方法
12. 怎么用mysql实现分布式锁
一面
自我介绍和项目
是否用过缓存(很少)
介绍一下多线程(线程,JAVA默认线程池,自定义线程池参数,线程安全集合,锁)
编程:一个有序数组和一个给定target,返回数组中target出现的次数 相关知识点: 数组二分
相关知识点: 数组二分
反问
二面
场景:系统每次推送8篇文章(show事件流),用户可能点击这几篇文章中的某几个(click事件流),现在要将这两种事件配对,如何做。
扩展:cache结构怎么设计,怎么尽可能准假遗漏少地匹配所有的事件,怎么估算cache大小,如果task出错怎么恢复
编程:一个大数组,所有元素互不相同,找topK(这里我说过堆和bitset,但是面试官更想知道一个基于快排的思路的解法,但是我不会)
编程:一个二叉树,层序遍历并输出,要求每一行开头输入行号
三面
三面面试官感觉好厉害,把我问懵了简直
自我介绍(主要介绍实习,项目,以及自己熟悉的领域)
是否熟悉本科的课程:操作系统,编译原理,计算机网络之类的。
平常使用什么系统,linux怎么看网络丢包率,怎么查复杂均衡问题,怎么看线程状态。实验室机器参数,几个物理核,几个虚核,几个线程。
一个网络连接池,coreSize=10, maxSize=100,怎么设计?当QPS增加的时候,怎么增加连接数,空闲时怎么降低连接数,说一下策略。(我答的类似线程池)
这样设计有什么问题,该怎么解决。
一个消息队列应该具有什么特点,怎么设计,主要解决什么问题
NoSQL数据库了解吗,这种数据库能够当成消息队列使用吗,为什么?
分布式系统应该具有什么特点?
反问
1 线程状态切换
2 当在记事本中写入文字时,操作系统后台都做了啥?
3 搭建一个SQL库表并查询,学生表、老师表、课程表,查询A老师学生的平均成绩,查询单科最高,最低成绩,查询出最受欢迎的课程以及最不受欢迎的课程。
4 输入一串字符,找出数量最多的前10个字符
5 机器人路径数(从左下角到右上角)
快手一面
1 类的加载过程 从class文件载入
2 A是B的父类,A中引用了B,在加载类的时候会出现死锁,分析原因
3 列举Java中的基本数据类型
4 String是基本类型吗,底层实现是什么样的,subString方法是返回一个引用还是新复制一个字符串。
5 单例模式懒汉写法,为什么要用volitile,不用会怎样?
6 HashMap实现原理 为什么会出现环
7 ArrayList和LinkedList区别 LRU
8 聚簇索引和非聚簇索引区别
9 得到B+树叶子节点存储的数据后 如果对应到数据库的一行
10 事务隔离级别 可重复度是如何保证读写一致性的
11 mvcc 中如果想读到当前事务之后版本号的数据,用什么指令?
12 二叉搜索树查找一个元素复杂度,链表查找元素复杂度,插入元素复杂度(考虑查找的时间)
13 算法题:二叉树的最右视图 bfs
14 概率题:
两个人抛硬币,先抛的人获胜的概率
两个人约定7:00-8:00见面,如果某个人先到了,只等待15min,问两人见面的概率多少?
快手一面:
记忆不是很清晰了,记到的就写一些吧~
1.Redis集群部署有哪些?Cluster模式下的Redis节点加入集群的过程(emmm……认真的说我不知道)
2.@Autowired和@PostConstruct注解的区别
3.@Config和@Bean的应用
4.了解RPC嘛
…忘了好多啊
快手二面
今天刚刚面完
1.先讲项目,因为项目用了一个工具,面试官问我,这个工具的底层是怎么实现的???(说了一些大概,但真的不懂啊啊啊啊啊…)
2.我来设计一个秒杀场景的系统,讲了一些缓存,消息中间件,布拉布拉的…面试官说,感觉你没有在实际场景中真正开发过??没有实习哭晕厕所~
3.问我leetcode刷了多少道题,这我…太难了
4.没了,就是没了……感觉有点凉
一面的话面试官主要根据你的简历来面:主要针对你的项目,看你项目中的知识来问问题。
这里只提一下Java相关的内容
1 介绍一下HTTP协议?
2 状态码 1xx 2xx 3xx 4xx 5xx
3 垃圾回收器了解哪些?
4 代码题:
给你一个二叉树,寻找路径(二叉树中的任意两个节点)的最大值。
对Java String的了解(说了常量池码点代码单元StringBuilder StringBuffer)这里问stringbuilder初始化数组大小没答上来应该是默认16
1.自我介绍,讲项目,扣细节 问了我怎么做的接口限流 这部分大概就是讲项目的亮点和项目的一些细节。
2. 项目的瓶颈在哪?就这么项目而言,如何实现高可用? (集群和分布式一套直接怼上去,主从,哨兵等等)
3. synchronized的代码分析和实现(锁对象和锁类)
4.juc包的简单了解
5.https流程(对称算法和非对称算法)
6.spring的IOC和aop ?问了几个ioc的问题。怎么实现依赖出入的 bean的生命周期 等等
7. nginx的负载均衡 如何配置 ?一些基本的策略?
8.悲观锁和乐观锁 ,用sql写一个乐观锁的例子
9.jdk8的新特性 问了Stream
10. 问了String 的底层 string相加和StringBuilder的append的方法有什么区别? 还有一个拓展的 我忘了 没听懂意思,他说没事
11.http的常用状态码。分别是什么意思?
12.在web开发中。假设大多数的url太长 ,怎么转成短链接? (数据库存储 然后重定向)
13.设计模式:设计模式考的挺深的。要理解一些常用的设计模式的思想,为什么这么设计? 设计模式的思想是什么?
14.hashmap arraylist linkedList的源码 api复杂度。
15.concurrentHashMap和Collections.SynchronizedMap hashtable的区别 分别是怎么实现线程安全的
16.mvcc
还有一些问题记不住了 。基本上简历上写了的都考了
问的确实挺全面的,但是面试官也非常好,基本上有些地方会给一些提示
基本的套路就是 项目中用的组件 比如mq,redis 一般会问几个问题
场景题也比较多
编程题:
给一个只包含±*/和正整数的字符串 求表达式的值。
一面(55分钟)
Java基础
==和equals区别
static修饰的成员变量运行时机
内部类和静态内部类区别
为什么要重写equals方法
HashMap底层数据结构,以及put方法和resize方法
说一下ConcurrentHashMap底层数据结构,以及如何保证线程安全的
说一下序列化,网络传输使用什么序列化
说一下泛型底层实现原理—类型擦除
并发
说一下JUC包下的同步工具
synchronized修饰方法和代码块区别
volatile如何怎么保证有序性和可见性
说一下线程池,以及线程池的几个核心参数,如果提交一个cpu密集型的任务怎么选取线程池
用volatile+synchronized写一个单例模式,用双重校验锁方法,说出两个if判断语句的作用
线程的几种状态,并指出在哪种状态下可以中断,中断原理
JVM
说一下几种引用方式,并说出其作用,以及垃圾回收时机
一个static成员变量如何进行内存分配及赋值
算法题
找到一个链表的倒数第k个节点
中间等待了15分钟~~~~
二面(50分钟)
0. 自我介绍
1.项目介绍
2.说几种创建对象的方式
3.静态代理和动态代理的区别
4.反射的作用及机制
5.说一下spring中IOC和AOP,还问了这个两个的英文全称是啥(差点没说出来)
6.项目中如何用到IOC思想的
7.http和https的区别
8.http如何在一个TCP连接上进行多次请求响应的
9.手写一个生产者消费者模式,用的ReentrantLock,为什么判断当前count是否满足生产或者消费时用while
10.i++是不是一个原子操作,说几种方法java如何保证对整型变量写操作线程安全的方法
11.ReentrantLock加锁操作后,在catch中捕获的是什么异常,为什么会发生这用异常
有什么问题要问他的,我问了两个,一个是对自己日后学习的建议,第二个是部门发展前景
一面:(约30分钟)
序数组排序,二分,复杂度
常见排序算法,说下快排过程,时间复杂度
有N个节点的满二叉树的高度。1+logN
单元点最短路的方法,时间复杂度
如何实现关键字输入提示,使用字典树,复杂度多少,有没有其他方案,答哈希,如果是中文呢,分词后建立字典树?
hashmap的实现讲一下吧,讲的很详细了。讲一下红黑树的结构,查询性能等。
Java中的垃圾回收讲一下,讲了分代,gc算法,gc root可达性分析等
死锁是怎么产生的
线程和进程的区别
进程的通信方式
CPU的执行方式
代码中遇到进程阻塞,进程僵死,内存泄漏等情况怎么排查。通过ps查询状态,分析dump文件等方式排查。
Linux了解么,查看进程状态ps,查看cpu状态 top。查看占用端口的进程号netstat grep
讲一下Tomcat的基本架构和组件,以及请求的整个流程。说了一下connector和container架构和servlet请求过程。
二面:(约30分钟)
快排的时间复杂度,冒泡时间复杂度,快排是否稳定,快排的过程
100w个数,怎么找到前1000个最大的,堆排序,怎么构造,怎么调整,时间复杂度。
先说了一下dfs递归实现。面试官说要优化。说了一下用迪杰斯特拉的思路,说可以。
四辆小车,每辆车加满油可以走一公里,问怎么能让一辆小车走最远。说了好几种方案,面试官引导我优化了一下,但是还是不满意,最后他说跳过。
hashmap的实现,hashtable,concurrenthashmap实现。
MySQL的索引,B+树性质。
Linux的cpu 100怎么排查,top jstack,日志,gui工具
Redis内存数据库的内存指的是共享内存么
Redis的持久化方式
秒杀系统的架构设计
三面:(约30分钟)
十亿个数的集合和10w个数的集合,如何求它们的交集。集合的数字不重复。
十亿和数找到前100个最大的,堆排序,怎么实现,怎么调整。
TCP和UDP的区别,具体使用场景呢。
TCP四次挥手讲一下过程,最后一次ack如果客户端没收到怎么办。
对于socket编程,accept方法是干什么的,在三次握手中属于第几次,可以猜一下,为什么这么觉得。
对于单例模式,有什么使用场景了,讲了全局id生成器,他问我分布式id生成器怎么实现,说了zk,问我zk了解原理不,讲了zab,然后就没问啦。
除了单例模式,知道适配器模式怎么实现么,有什么用
回到网络,刚才你说到直播场景,知道直播的架构怎么设计么,要点是什么,说了几个不太对,他说要避免广播风暴,答不会。
问了一下最近看什么书,什么时候开始写博客的
问了还有几轮面试,他说这轮我可以过,有点小惊喜
一面:
1 写一个选择排序或者插入排序
2 写一个生产者消费者
3 Java多线程了解么,什么时候一个int类型的操作是不安全的,自加呢,赋值呢。
如果使用volatile修饰的话有什么作用。
4 MySQL和redis的区别是什么
5 为什么MySQL和Redis都要使用独立进程来部署,开放端口来提供服务,为什么不写在内核中。
6 有一个场景,多线程并发,为每个线程安排一个随机的睡眠时间,设想一种数据结构去唤醒睡眠时间结束的线程,应该用哪种结构,答应该用优先级队列,也就是小顶堆,顶部是剩余睡眠时间最短的那个线程。
7 好像就是这些了。
二面:
1 项目
2 多线程
3 一道算法题,一个二维矩阵进行逆置操作,也就是行变列列变行。刚开始我理解错了,直接用一维数组转储再重新填入新数组。
面试官说可以不用一维数组么
然后解答的过程中才发现我理解错了。改了一会才搞定。
4 扩展一下,二维数组存在500g的文件中,怎么做才能完成上面算法的操作,我就说先按行拆分,最后再拼接。
5 扩展两下,一行数据就会超出内存,应该怎么做,那就按列拆分,最后合并。
6 知道服务的横向扩展和纵向扩展么,刚开始理解错了,后来就说是提高单机性能,以及扩展成集群。
7 cap介绍一下吧,为什么只能3选2
8 线程与进程
9 tcp和udp的区别
10 get和post的区别
11 并发量大概多少,做过优化吗
自我介绍
项目介绍
做题
求1到n的和(递归和遍历,等差数列公式O(1))
二叉树中最深叶节点的节点和
get和post的区别,post为什么是两次TCP连接,解释下幂等性
口述下工厂模式,抽象工厂和简单工厂
快手二面
自我介绍
项目介绍
项目中负责的模块
项目难点,亮点,怎么解决
项目中订单模块
说下堆和栈
进程和线程的区别
如何理解线程安全
如何保证线程安全
Java中synchronized的原理,synchronized有什么不足,一定线程安全吗
volatile原理
信号量和互斥锁的区别,作用,场景
分布式锁,redis分布式锁原理,需要注意什么
redis挂了怎么办
说下主从,说下持久化
说下页式存储管理,虚拟内存
TCP三次握手说下
如果TCP服务端一直没响应,客户端怎么处理
http和https区别
https原理
做题
删除链表倒数第n个节点
股票问题
闲聊
一面**(一个小时十分钟)**
1.自我介绍
2.说说B+树和B树的区别,优缺点等?
3聊聊Spring,主要IOC等等
4多线程JUC包下的一些常见的类,比如CountDownLatch、Semaphore等
5.锁的概念,锁相关的关键字,volatile,synchronized。还比较了ReentrantLock与synchronized。
6.你了解哪些收集器?CMS和G1。详细谈谈G1的优点?什么时候进行Full GC呢?
7.Spring中涉及的一些设计模式
8.算法题:无序数列中求第k大的数(维护最小堆,然后依次遍历,与堆顶比较)
9.MySQL创建索引的原则,好处
怎么实现一个线程安全的计数器?
二面**(四十多分钟)**
设计模式:讲了单例,工厂方法,抽象工厂,策略模式,观察者模式,代理模式,还顺便讲了下spring动态代理的实现原理
线程池有哪些参数?分别有什么用?如果任务数超过的核心线程数,会发生什么?阻塞队列大小是多少?
HashMap的底层数据结构
红黑树的具体结构及实现,红黑树与查找树的区别体现
接着聊ConcurrentHashMap,底层实现
HashMap哈希函数的认识,JDK1.8采用的hash函数
数据库索引,索引底层的实现,B+树的结构以及与普通查找树的优点
TCP三次握手四次挥手,四次挥手过程中服务端的哪几种状态,哪几种包
已经有一个查询好友的接口,设计一个微信朋友圈,可以实现发表朋友圈,添加评论,查看评论等功能。主要是设计数据结构
三面**(50分钟:主要分布式这块)**
你对快手的了解,和抖音的区别,聊项目
项目中用到dubbo?那你说说什么是rpc框架?和http调用的区别是什么?
Redis有哪些数据结构?持久化方案和区别?
Redis哨兵、集群的设计原理和区别?
Redis缓存和数据库会存在一致性问题吗?怎么解决
Kafka怎么保证数据可靠性?讲了生产者端发送消息到broker持久化,分区和副本机制,消费者消费消息的at-least-once和at-most-once?怎么实现Exactly-Once?
一面基础 二面算法
一面:
如何建立索引:1.create 索引类型 索引名 on 表(字段) 2.alter table 表名 add 索引类型 索引名 (字段)
使用索引时要注意什么:好多原则巴拉巴拉
Hashmap和currentHashMap:hashmap线程不安全,currentmap线程安全。
CurrentHashMap如何保证线程安全:ConcurrentHashMap引入了一个“分段锁”的概念,具体可以理解为把一个大的Map拆分成N个小的HashTable,根据key.hashCode()来决定把key放到哪个HashTable中。在ConcurrentHashMap中,就是把Map分成了N个Segment,put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中
Redis的作用:
为什么用redis做缓存:redis的缓存可以持久化,redis可以实现分布式缓存,redis’可以处理每秒百万级的并发,redis有缓存过期机制,redis有丰富的API
**Tcp三次握手:**SYN->SYN+ACK->ACK
**四次挥手:**FIN->ACK;FIN->ACK
当一段连接已经断开时,另一端再发数据,此时如何防止数据丢失://还未解决也没有搜到。。。
接口和抽象类:
抽象类默认用abstrct 修饰。修饰限定符是public 或者private的,子类必须是西安它的所有方法,如果没有全部实现,则子类也要用abstract修饰。抽象类不能使private的不然子类不能继承。
接口中的变量默认是public static final的,且必须给出初始值,方法默认使用public abstract的,从jdk1.8开始,可以有具体实现的默认方法。
一个类可以实现多个但是只能继承一个抽象类
常用的线程池:
CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,相当于无限大。当需要时创建线程来执行任务,没有需要时回收线程
SecudleThreadPool:周期性的执行任务的线程池,按照某中国特定的计划周期性的执行线程中的任务。有核心线程也有非核心线程,非核心线程的大小为无限大,用于周期性的执行任务。
SingleThreadPool:只有一条线程来执行任务,适用于顺序执行任务的场景。
FixedThreadPool:定长的线程池有核心线程,核心线程就是最大的线程数,没有非核心线程。
二面:
**项目用到了多少张表:**11张
Solr是如何和数据库连接的:
1.在mysql中建立数据库表
2.将数据库的驱动文件加入solr的lib文件夹中:mysql-connector-java-版本号.jar
3.在自己创建的core实例的conf文件中进行数据配置
4.启动tomcat并访问solr,算则dataimport,点击excute
5.点击query查询后方可显示数据库信息
6.https://blog.csdn.net/gaosilingqwer/article/details/79891278
分页是如何读取数据是一次把所有数据传过去前端分页吗?
使用分页插件在前端分页,不能再数据库中一次将所有信息查出返回给前端,这样数据库压力太大。使用sql语句,limit start n;参数含义 start-页码,n-每页显示的条数
使用springboot jpa Pageable pageable =PageRequest.of(pageNumber,pageSize); pageSize行数,pageNumber页码数
Redis重启数据会清空吗?
可以进行持久化配置,有两种方式(持久化是说可以将内存中的文件保存再数据库中,或者磁盘、xml文件等)
RDB 方式可以保存过去一段时间内的数据,并且保存结果是一个单一的文件,可以将文件备份到其他服务器,并且在回复大量数据的时候,RDB 方式的速度会比 AOF 方式的回复速度要快。
AOF 方式默认每秒钟备份1次,频率很高,它的操作方式是以追加的方式记录日志而不是数据,并且它的重写过程是按顺序进行追加,所以它的文件内容非常容易读懂。可以在某些需要的时候打开 AOF 文件对其编辑,增加或删除某些记录,最后再执行恢复操作。
Zookeeper是用集群吗?一个节点宕机后怎么办?
用集群,一个主节点剩下的都时备份节点,注册中心对等集群,任意一台宕机就会自动切换到另一台。注册中心全部宕机后,服务提供者和服务消费者仍然能通过本地缓存通信。
对zookeeper的理解:https://www.cnblogs.com/takumicx/p/9508706.html
对dubbo的理解:https://segmentfault.com/a/1190000019896723
B+树:非叶子节点不存储数据,作为索引,叶子节点存储数据,用链表进行连接。
红黑树:所有节点非黑即红,根节点是黑色,任意节点到它每个叶子节点的所有路径都包含相同的黑色节点。
**b树和b+树的区别:**b树:有序数组+多差平衡树;B+树:有序数组链表+多差平衡树
索引为什么不选择b树:b树的数据信息存放在每个节点,遍历采用中序遍历,遍历1-100可能会涉及到不同的层次。而B+树直接从叶子节点扫一遍就完了。B+树支持range-query。
一面
简单自我介绍(包括项目)
问了下我实验室情况,由于面试官是北邮的(通信很强),简单问了下我文章的事情
Spring Aop的实现原理?(回答是使用了代理模式)你还知道哪些框架使用了代理模式?
静态代理和动态代理的区别?
看你项目里面使用了httpclient,那么httpclient是怎么配置的呢?
Tomcat IO优化?(不会。。。)
http1.0和http2.0的区别?(我回到是1.0里面的长连接一次连接中的多个请求串行执行,2.0里面可以并发执行),然后面试官问我串行执行和并发执行是什么意思?(解释了下,他说我没理解这两个的区别,顺便举了个栗子,说要是我先打开一个网页,再打开一个,岂不是不行?其实我没听明白,也不确定前一个网页要是没刷出来,后面那个到底能不能刷出来)
实际场景题:一个签到系统,签到有奖,连续签到的话奖励会递增,怎么实现连续签到判断?(我说的是redis打时间戳来实现,用户id作为key值,时间戳为value,其中value里面是一个list集合,关键在于怎么判断是连续一天还是间隔了一天,可以将上一个时间戳计算还有多久一天结束,记为t0,接着新添加的时间算出间隔时间,记为T,将T-t0,与24进行比较即可)
当有很多用户同时进行签到,那么会有大量数据在redis数据库里面,该怎么缓解这种压力?(我开始回答是利用redis内存淘汰机制来处理缓存,使用LRU算法,面试官说问的不是这个意思,然后我回答了持久化到硬盘里面)
redis持久化的方式有哪些?
struts用的是什么?(struts2)那么考虑过登陆系统里面的action是否会发生线程安全问题么?(会发生线程安全问题,没考虑过。。。)
基本就记得这些了,然后马上约了二面…
二面
简单自我介绍下
java里面的对象是值传递还是址传地?
hashMap是线程安全的么?什么时候会发生线程安全问题?哪些又是线程安全的呢?(我回答了ConcurrentHashMap)那么ConcurrentHashMap中两个线程定位到了同一个位置的时候,一个进行查询,一个进行插入,二者是同步还是异步执行的?
Map a = new HashMap();
a.put(1, 1);
a.put(2, 2);
void method(map a){
a = new HashMap();
a.put(3, 3);
}
最后a里面有哪些数据?
4.在一张表里面查找年龄最小的一行数据,用SQL写?(不会。。。挂点一)后面补问了一个关键字,应该是用于寻找最小的,
我回答不会(挂点一plus)
数据表
id name age group
1 张三 24 1
2 李四 25 1
3 王五 21 2
4 赵六 18 2
5.redis里面实现排行榜功能?sorted set底层是怎么实现的?(不会,挂点二)
6.utf-8和unicode的区别?字符和字节的区别?(不会,挂点二。。。这个真不应该直接说不会,很让人失望)
7.算法题:求一个满二叉树的镜像(先翻转一个节点的左右子树,再进行递归即可)
8.你有什么想要问我的么?
9点半开始面试,第一次来西二旗,8点多点就到了,在大厅等待区域等着,顺便看下美团的面经。
一面:
自我介绍,聊了一下为什么转专业,为什么考研
== 与 equals()区别?过
重写和重载?
面向对象有哪些特点,与面向过程相比有哪些优势?过
聊一下JVM的运行时数据区吧?栈区域能详细说一下嘛?
这个栈没有详细了解过。。
运行时数据区哪些是线程共享的?堆和方法区
异常和错误类了解过没有?怎么分类的?过
说一下异常的分类?
集合类问了一点,具体忘记了
map是怎么实现的1.8之后做了什么优化?(链表变红黑树,昨天还看到了,一紧张忘记了。。WTF)
线程安全的map有哪些?(3个)
concurrentHashMap实现原理?(1.7 1.8各分别说一下)
volatile能详细说一下嘛?(这个题答得不太好)
wait和sleep区别?如何实现线程通信?wait和notify原理?(第三个不会,面试官给我讲了一下,,似乎也有点不太明白)
synchronized原理?(我把锁升级原理说了一下)
synchronized是什么性质的?volatile呢?
你刚刚说偏向锁、轻量级锁、重量级锁各体现在哪个方面?(答得不太好,面试官又给我讲了一遍。。。)
说一下线程池的优势吧?过
你平时都用哪些线程池?知道哪些?过
线程的五种状态了解吗?过
就绪状态和阻塞状态有何不同?(这题我直接懵了,面试官又给我讲了。。。)
讲一下可重入锁?(这个前两天刚看,说的还可以)
Spring的IOC和AOP讲一下?过
三次握手和四次挥手?
TCP和UDP?
MySql事务的隔离级别说一下?其中各解决了什么问题?
脏读不可重复读幻读
读未提交111
读已提交011
可重复读001
串行化000
MySql内部用的什么索引B+Tree
B+Tree和BTree的区别(送分题,没答上来)
手写算法题:快排。
一面从9点40左右开始,面试到10点半,50分钟。。。然后面试官让我在会议室等待二面。
二面:
进来一位技术大佬(看面相就知道)
先自我介绍balabalabala…
组原和网络学过没有?
答:没有系统学过
重写和重载?
我看你项目用了springboot+springcloud,简单介绍一下吧?balabalabala。。。
然后从项目开始入手,你用到了feign,知道调用原理吗?(没答上来。。)
你用redis做什么?(单点登录,实时数据缓存)
redis持久化知道吗,你用的哪种方式,区别?(我用RDB。。。然后区别说了一下)面试官问?还有吗我实在想不到了。。
redis的发布订阅用过没有?(答:没有)
说一下SpringMVC处理流程,从拦截器,过滤器的角度。。我把一下组件和调用关系说了,拦截器没有用过,我说都是自己写的过滤器。。
然后给我出了一个题,在一个controller中有三个方法(1)(int id,String name) (2)(User user) (3)(@RequestBody User user) 前端怎么传递参数?请求方法
@requestmapping 与@restmapping区别?
写一个sql吧,查询学生选课最多的课程前5名。先分组,在筛选,很简单。巨紧张第一次写错了,第二次重新写写对了,但是把过滤忘记了。。粗心大意
Eureka的特点。。(注册中心,保证了AP)
你的项目既然用feign了为什么还需要Eureka?
application.properties和xxx.yml你喜欢用哪个?
application和bootstrap谁先启动?加载顺序?又问了一点原理?
说一下springcloud的组件吧?
写了一个算法题,中等题吧,但用双指针把大体思路说了,面试官说你这样得考虑很多因素啊!我说确实是,然后我说这个用动态规划递归也可以。
你还有什么问题要问我吗?
结束。
1.要不先做下自我介绍?说一说你最近做的那个项目?然后针对简历提了几个问题。你哪年生的啊?我看你简历上没有。
2.我看你简历里面说做过mysql的优化,说说你都做过哪些优化或者优化的思路?
数据库的索引了解吗?说一下索引的原理?聚集索引和非聚集索引了解吗?了解mysql的回表吗?
mysql实现分布式锁了解吗?还有没有其他更好的方式?
3.说一下事务的一些东西?你对事务的了解有哪些?说说数据库的乐观锁和悲观锁?
4…Redis有哪些持久化方式?你们在项目中一般怎么做持久化?如何实现集群和高可用?
5.Java中有哪些锁?synchronized与Lock有哪些区别?什么是公平锁和非公平锁?他们的底层怎么实现的?
AQS原理了解吗?能不能详细介绍一下?
6…说一下线程池的原理?ExcutorService下的四种线程池分别用在什么场景下?为什么单线程池和固定线程池使用的任务阻塞队列是LinkedBlockingQueue(),而缓存线程池使用的是SynchronousQueue()呢?
7.说一下violatile关键字吧?刚才你提到可见性?他是如何保证可见性的?
8.说一下GC吧,什么时候进行Full GC呢?你了解哪些收集器?CMS和G1。详细谈谈G1的优点
最后写了一个编程题。
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
这个是leetcode原题。
写完面试官问方便来北京现场面试吗?你还有什么想问的?后续有什么消息hr会通知你。
紧接着就约了二面
二面比较注重设计
面试官上来就让设计了一个小型的社交系统。从数据库设计开始,然后设计架构。这个花了很长时间。
然后问了下dubbo的原理,有没有看过dubbo源码?dubbo的容错机制?
然后又是写题了
是股票买卖的一道题
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
最后还是有什么想问的?
3月中旬投了很多简历,可是没有一个公司找我面(简历太菜了吧···),还好快手把我捞起来了(orz)。5月5号下午两面,今天等到hr电话沟通入职的事项。
快手面试很基础,但是考察的也挺细致,下面是面经,分模块记的
一面(55分钟)
Java基础
==和equals区别
static修饰的成员变量运行时机
内部类和静态内部类区别
为什么要重写equals方法
HashMap底层数据结构,以及put方法和resize方法
说一下ConcurrentHashMap底层数据结构,以及如何保证线程安全的
说一下序列化,网络传输使用什么序列化
说一下泛型底层实现原理—类型擦除
并发
说一下JUC包下的同步工具
synchronized修饰方法和代码块区别
volatile如何怎么保证有序性和可见性
说一下线程池,以及线程池的几个核心参数,如果提交一个cpu密集型的任务怎么选取线程池
用volatile+synchronized写一个单例模式,用双重校验锁方法,说出两个if判断语句的作用
线程的几种状态,并指出在哪种状态下可以中断,中断原理
JVM
说一下几种引用方式,并说出其作用,以及垃圾回收时机
一个static成员变量如何进行内存分配及赋值
算法题
找到一个链表的倒数第k个节点
中间等待了15分钟~~~~
二面(50分钟)
0. 自我介绍
1.项目介绍
2.说几种创建对象的方式
3.静态代理和动态代理的区别
4.反射的作用及机制
5.说一下spring中IOC和AOP,还问了这个两个的英文全称是啥(差点没说出来)
6.项目中如何用到IOC思想的
7.http和https的区别
8.http如何在一个TCP连接上进行多次请求响应的
9.手写一个生产者消费者模式,用的ReentrantLock,为什么判断当前count是否满足生产或者消费时用while
10.i++是不是一个原子操作,说几种方法java如何保证对整型变量写操作线程安全的方法
11.ReentrantLock加锁操作后,在catch中捕获的是什么异常,为什么会发生这用异常
12.有什么问题要问他的,我问了两个,一个是对自己日后学习的建议,第二个是部门发展前景