(从面试全职到妥协实习生,沟通了几百个hr,面试了30+公司,一度怀疑自己到底适不适合这一行,如此内卷真的要走下去吗?门槛越来越高,待遇越来越低)
本人现在广州白云区租房,投递大部分也是广州,所以基本无线上面试。
线下面试首先跟面试官约好时间【一定要确认好需要带过去的东西,例如简历、笔、身份证等;确认公司位置、进去的方式(不然等到了公司楼下在联系面试官、找方向可能会浪费很多时间,本人深受其害)】
到公司前台说“我是过来面试的”,然后小姐姐就会让你签到登记,然后给一份表格和笔试题自行填写【有那么一两家公司没有笔试,但是基本都是有的】
填完笔试开始面试:
面试前我会先去百度、看准、职友集等看该公司的大致情况以及面试情况,先做个提前准备
面试过程中先自我介绍(最好有自己固定的一套话术):
本人来自xxx学校,在学校表现如何(我一般说学校能力优秀,在学校每年获奖学金等,简单亮出自己一点亮点),然后在xx平台/地方看到贵公司的招聘信息,刚好最近本人在寻求新的挑战新的工作机会,并觉得自身条件符合,便前来应聘。之前有了解到贵公司的业务方向有xxxxxx,能感受到会有很多的机会和挑战,是一个更好的平台(简单说一下对公司的了解)。
然后本人有java基础,熟悉xxxxxxx(讲述自己技术栈),然后举个例子说明自己拥有某些能力(如学习能力强、具备一定的阅读文档的能力等,我举例通过自己阅读文档完成需求)。
说明自身的性格特点等,如能抗能打(能抗压能挨打)、学习能力优秀、会总结、做笔记写博客、好相处、骚气蓬勃气氛组、乐于分享喜欢请教等。
接下来就是面试官顺着简历问了,有啥答啥。
问到项目,我的回答流程:
先答做这个项目的背景(为什么要做这个东西),项目的架构、用到的技术,拥有什么功能
我还有什么问面试官的
1、我想知道贵公司的业务范围是?
2、我想知道贵公司目前的开发团队规模是?团队中各类型的人员分别是?(了解前后端分别多少人,是不是有学习的空间和是不是要自己前后端都写)
3、公司的技术栈是什么?(同样,了解公司有没有发展空间)
4、初期的入职培训是如何,进去之后的日常工作是什么?(虽然有这么想,但基本我都没问过,因为老是忘记)
5、您觉得今天我的面试表现如何,我想听听您的评价,如果有不足的我回去可以进行改进。(这个是我的底牌,一可以大概感觉出自己有没有戏,二是可以给面试官一个我有良好的学习态度的印象,三是我真的可以知道自己的不足,就很香)
谈薪
我投降,我不会谈,都是他们给定价,基本都变不了了,然后待遇一次比一次低,到最后我已经绝望了
sychornized 和voliate
数据结构了解过吗?
我答:数组、链表、栈、队列、树(二叉树、红黑树)、图、堆、哈希表
谈谈集合
我答:有三种集合,List、Set、Map
其中List是有序集合、set是无序、map是键值对集合
list下常用有ArrayList、LinkedList、Vector,而ArrayList和Vector区别是Vector是线程安全的
set下常用有HashSet、LinkedHashSet、TreeSet,而TreeSet可以实现排序
map常用有HashMap,HashTable,LinkedHashMap,其中HashMap和HashTable的区别是HashMap可以存储一条键值为null的值,HashTable不可以,且HashTable是同步的线程安全。
HashMap底层实现原理
jdk1.7以前是数组+链表,jdk1.8以后是数组+链表+红黑树。
当哈希桶的长度是8时就会变成红黑树,变为6时又会变成链表。负载因子是0.75,初始化大小时16,当大小到12(16*0.75=12)时,就会进行扩容,每次扩容都是2的整次幂
关于HashMap中初始化大小为什么是16? 为什么链表的长度为8是变成红黑树?为什么为6时又变成链表?感觉详细可以看这里
springIOC和AOP
对于Spring,核心就是IOC容器,这个容器说白了就是把你放在里面的对象(Bean)进行统一管理,你不用考虑对象如何创建如何销毁,从这方面来说,所谓的控制反转就是获取对象的方式被反转了。既然你都把对象交给人家Spring管理了,那你需要的时候不得给人家要呀。这就是依赖注入(DI)!再想下,注入方式有两种,构造方法注入和setter方法注入
对于AOP,举例说明:比如你写了个方法用来做一些事情,但这个事情要求登录用户才能做,你就可以在这个方法执行前验证一下,执行后记录下操作日志,把前后的这些***与业务逻辑无关的代码抽取出来放一个类里***,但是在运行的时候,两个毫无相关的类在运行内存中又会结合在一起,这个类就是切面(Aspect),这个被环绕的方法就是切点(Pointcut),你所做的执行前执行后的这些方法统一叫做增强处理(Advice)。
请讲一讲你对JVM内存模型的了解?
JVM内存空间分为五部分,分别是:方法区、堆、Java虚拟机栈、本地方法栈、程序计数器
方法区主要用来存放类信息、类的静态变量、常量、运行时常量池等,方法区的大小是可以动态扩展的
堆主要存放的是数组、类的实例对象、字符串常量池等【String s1 = "abc"放在常量池,使用了new关键字则放堆内存】。
Java虚拟机栈是描述JAVA方法运行过程的内存模型,Java虚拟机栈会为每一个即将执行的方法创建一个叫做“栈帧”的区域,该区域用来存储该方法运行时需要的一些信息,包括:局部变量表、操作数栈、动态链接、方法返回地址等
本地方法栈结构上和Java虚拟机栈一样,只不过Java虚拟机栈是运行Java方法的区域,而本地方法栈是运行本地方法的内存模型。
程序计数器,程序计数器可以理解为记录着下一条将执行代码指令的地址
方法区和堆都是线程共享的,在JVM启动时创建,在JVM停止时销毁;而Java虚拟机栈、本地方法栈、程序计数器是线程私有的,随线程的创建而创建,随线程的结束而死亡。 【所以这就往往有一个问题:进程之间是不共享内存的,那么进程与进程之间如何进行沟通】
cookie与session区别
1、cookie存放客户端,session存放服务器。不考虑安全性的数据可以存放cookie
2、session的ID识别是依赖于cookie的,客户端发起请求时,发送的cookie带有session的id值,如果前端禁用cookie的话,后端的session也会失效
3、 Cookies是属于Session对象的⼀种。但有不同,Cookies不会占服务器资源,是存在客服端内存或者⼀个Cookie的⽂本⽂件中;⽽Session则会占⽤服务器资源。所以,尽量不要使⽤Session,⽽使⽤
Cookies。但是我们⼀般认为Cookie是不可靠的,Cookies是保存在本机上的,但是其信息的完全可⻅性
且易于本地编辑性,往往可以引起很多的安全问题Session是可靠地。但是⽬前很多著名的站点也都⽤
Cookie。
get和post区别(略)
Redis的数据类型
五种:String、List、Map、Set、ZSet(Sort Set)
Redis持久化
两种:RDB和AOF类型
区别:
类型 | 简介 | 优点 | 缺点 |
---|---|---|---|
RDB | RDB是在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复 | 使用单独子线程进行持久化,主线程不会进行IO操作,保证了Redis的高性能 | RDB是间隔一段时间进行持久化,如果持久化期间Redis发生故障,会发生数据丢失,所以更适合数据要求不严谨的时候 |
AOF(Append-only file) | 将“操作+数据”以格式化指令的方式追加到操作日志的尾部,在append操作返回(已经写入到文件或者即将写入),才进行实际的数据变更,“日志文件”保存了历史所有的操作过程;当server需要数据恢复时,可以直接replay此日志文件,即可还原所有的操作过程。AOF相对可靠,它和mysql中bin.log、apache.log、zookeeper 中txn-log简直异曲同工。AOF文件内容是字符串,非常容易阅读和解析。 | 可以保持更高的数据完整性,如果追加file的时间是1s,此时Redis发生故障那么最多会丢失1s的数据;且如果日志写入不完整支持Redis-check-aof来进行日志修复;AOF文件没被rewrite之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的flushall) | AOF文件比RDB文件大,且恢复速度慢 |
Redis缓存雪崩
缓存雪崩产生的原因
缓存雪崩通俗简单的理解就是:由于原有缓存失效(或者数据未加载到缓存中),新缓存未到期间(缓存正常从 Redis中获取,如下图)所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力, 严重的会造成数据库宕机,造成系统的崩溃。
解决方案:
1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。 比如对某个key只允许一个线程查询数据 和写缓存,其他线程等待。 虽然能够在一定的程度上缓解了数据库的压力但是与此同时又降低了系统的吞吐量。 public Users getByUsers(Long id) { // 1.先查询redis String key = this.getClass().getName() + "-" +Thread.currentThread().getStackTrace()[1].getMethodName() + "-id:" + id; String userJson = redisService.getString(key); if (!StringUtils.isEmpty(userJson)) { Users users = JSONObject.parseObject(userJson, Users.class); return users; }Users user = null; try { lock.lock(); // 查询db user = userMapper.getUser(id); redisService.setSet(key, JSONObject.toJSONString(user)); } catch (Exception e) { } finally { lock.unlock(); // 释放锁 } return user; } 注意:加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着 的,这是过来1000个请求999个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法。 2: 分析用户的行为,不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
谈谈mysql调优
在经常需要检索的列上建立索引,但一个表的索引最好不要超过6个;优化SQL语句,例如少在where后判空、not in、做计算、模糊查询like 的‘%’不放前面,否则都会导致引擎放弃走索引而全表扫描
mysql存储引擎
主要是myisam,innodb的区别
区别 | InnoDB | MyIsAM |
---|---|---|
事务支持 | 支持 | 不支持 |
存储结构 | .frm 存储表结构 .ibd存储数据和索引 | .frm存储表结构 .MYD存储数据 .MYI存储索引 |
表锁差异 | 支持事务和行级锁,行锁只在where的主键有效,非主键的where都会锁全表 | 只有表级锁 |
表主键 | 如果没有设定主键或者非空唯 一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。 InnoDB的主键范围更大,最大是MyISAM的2倍 | 允许没有任何索引和主键的表存在,索引都是保存行的地址。 |
表的具体行数 | 没有保存表的总行数 (只能遍历),如果使用select count() from table;就会遍历整个表,消耗相当大,但是在加了wehre条件后, myisam和innodb处理的方式都一样。 | 保存有表的总行数,如果select count() from table;会直接取出出该值。 |
CURD操作 | InnoDB:如果你的数据执行大量的INSERT或 UPDATE,出于性能方面的考虑,应该使用InnoDB表。DELETE 从性能上InnoDB更优,但DELETE FROM table 时,InnoDB不会重新建立表,而是一行一行的删除,在innodb上如果要清空保存有大量数据的表,最好使用 truncate table这个命令 | 如果执行大量的SELECT,MyISAM是更好的选择。 |
外键 | 支持 | 不支持 |
@SpringApplication
包含:@EnableAutoConfiguration 、@SpringBootConfiguration、@ComponentScan
持续更新补充中…