Edgar校招后端学习--简历技术栈建立过程总结(持续更新)

写在前面
当自己真正开始梳理以往学过的知识,会发现很多点有遗忘或者当时了解的就不是很透彻。可以参考相关学过的课程,和别人的简历对自己的技术栈进行一个梳理

后面反思了一下
后面插入一条主线,其实以下问题是基于JUC开发的相关问题。为什么以前自己不够了解这些问题,或者说了解完容易忘记,因为做的很多项目都不是并发的,没用线程,也没用事务、更没用多事务,多人同时登陆。所以姑且这块叫做**JUC面试部分吧!**而且我觉得再小的公司也得有并发的情况啊,所以我觉得这块还是挺重要的,后期想真正的落实到项目中。
1.这一块的理解今天又加深了一下(不知正确与否),其实在实际生产中,还是主要在dao层这块,在数据库这块。http协议以及服务器的架构,他们本身就支持很好的隔离机制,只有到我们自己操作crud到数据库或者缓存中的时候,那时候我们的多线程之间对同一块内存或者同一行数据进行操作的时候,要格外小心。


JAVA–线程相关考点

  • 理解这部分的话,第一要理解资源的概念,比如说i现在这个整形,在并发下就是一个资源,有可能两个线程同时读到了他,但是而且要进行相应的操作。这是资源的理解,像同步代码块,同步方法都是java里面对并发下资源的控制。

  • 第二理解并发的话,重点理解和观察出哪里是非原子性操作,什么叫非原子性操作。就是说白了,我这个操作,我执行的时候,不可能切出去,别的线程不可能打断。就一步就能完事的操作。

  • 你去搜,有基本三大类,我自己是不太熟悉。我的经验就是一旦是两行代码了,尤其if这种基本不是了,两行你就有情况先判断然后等着,又来一个判断,然后你去操作,他操作的时候很明显就把你的操作覆盖掉了(我说的是cpu轮询的时候)。

  • 再一个++这种操作,或者i+=n这种操作(这个操作类型,在hashmap扩容的时候就有,现有长度等于原长度+扩容长度)–所以hashmap不安全

  • 补充的话 还有,除了 long double 基本类型的复制,就直接一个=号这种;引用这是原子性的操作,还有一个原子包里面都是原子性的,所以说运算来说非原子性的概率很大
    线程的五种状态

  • 新建就你new了什么的 就绪

  • start执行了以后就就绪了–sleep与wait()的notify()也是就绪状态等着操作系统来找你

  • run不用说跑起来了

  • 阻塞状态,阻塞、就绪、运行三者之间一个三角。阻塞之后只能就绪,不能直接运行。那么说sleep和wait都是让线程进入阻塞态

  • 死亡状态

1.说下Sleep和wait的区别
sleep()方法

  • sleep方法属于线程类。

  • sleep的线程,首先不一定是调用了同步锁。

  • 如果调用了同步锁的话,它不会释放掉同步锁。

  • 他仅仅让出cpu,但是锁住的相关对象其他线程无法调用。

  • 当sleep时间到的时候,会自动重新抢夺cpu资源,但是不一定能够抢夺到。
    wait()方法

  • wait方法属于object类,同时notify()也是。

  • 这两个哥们配合使用,表示线程挂起与恢复。

  • 此时线程一定调用同步锁,并且他会释放掉同步锁,继续回到线程池中等待。

  • 等待其他方法调用notifiy()来通知他参与到cpu的竞争(此时解除阻塞状态,但是要看是否wait()方法设置了超时时间,如果设置了超时时间,不用等到其他进程使用notifiy方法,一样会解除阻塞),但是不是notifiy()方法一调用他就能拿到cpu资源,此时还是要等待其他方法调用wait(),这样资源才会被释放掉。

  • 相比较sleep方法可以在任意位置执行,wait只能在同步代码中执行。

  • wait方法使用时要捕获异常。

相同点 都可以被interrupted方法中断

synchronized与Lock区别
首先synchronized是java的一个关键字,而Lock是一个接口
关键字会有锁升级等过程,这个以后再聊,关键字不会造成死锁,接口会造成死锁,所以说你在finally里面必须给他解开、释放掉
。关键字会释放掉自己手里的资源,分为两种,要是我拿到这个锁,我会执行完,就放。我要有异常,jvm会帮关键字释放锁。
但是Lock可以通知线程相应终止等待资源,但是关键字不会他会老老实实让其他线程等着,等着我获得这个锁。
关键字适用于少量同步的时候,接口适用于大量同步的时候。因为接口可以实现读写分离,一块读,一块写。简单来说接口比较灵活,关键字比较单一,竞争不激烈的时候使用关键字管理就行。


JAVA–字符串常见考点

聊聊String、StringBuffer、StringBuilder
stirng

  • 1.首先来讲,字符串的话底层是字符数组。
    2.string本身的数组是被final修饰的,所以打死他他也不能变,所以我们对string做的任何操作都不会改变原来的字符串。
    3.另外string的,这种形式string=’abc‘ 采用的是池化思想。 也就是说他会先从池子里去找,找了没有再创建一个,又得话把池子的地址返回给你。
    stringbuffer与builder的安全问题
    安全问题统一思路,看底层源码是不是被相关关键字修饰了,synchronize的常见关键字。
  • 这两个方法都有append追加 区别是 buffer里面是被修饰过的,另一个没有。另外因为追加多了,需要扩容,那块也是不安全的。

*说说到底是哪
下面这行代码出现在append里面,设想两个线程同时操作这种非原子性的运算,可能线程1算完是11,线程2算完也是11 这个值就等于11了,但其实应该是12.而且扩容还有可能引起复制吧,复制的时候有可能你就给别的线程的值覆盖上。

count += len;

JAVA–常见关键字考点

  • 上面的synchronizedlock算一个吧
  • 常考的就是final家族–final finally-finalize
  • 首先fianl就是一个,不可变的代言词,他修饰的的变量叫常量,初始化后不可变-方法不能重载-类不能继承,常见的比如说 string就被final给,下咒了,看上面他是不可变的。
  • finally,没啥说的,就是在try-catch 配合使用,你像一些必须释放掉的资源(上面说的解锁操作啊、数据流的关闭啊这都得用它)
  • finalize其实是GC,也就是jvm相关知识那块的,简单说,他来自object对象里面,所以说对象都有这个,告诉gc,来你收了我,但是GC也是爱理不理的,并不一定好使,这个方法后面也被摒弃了,还是老老实实手动释放,或者在finally里面释放
  • 再说一下static,这个字接触的最早(psvm的main方法嘛)
    简单来说就是静态的意思,,静态这个意思就是全局只有一份,你在那修改都是修改这一份。静态方法里面必须调用静态的变量。
    还可以修饰方法,对,类.方法名,所以就脱离了new
    还有静态代码块,类加载的时候,初始化一次。
    这都是以前的,今天我开始学习单例模式,又对这个字产生了浓厚的兴趣。单例模式中的饿汉模式我做了一个小实验。
 public class lazy {
     

    private  static lazy lazy=new lazy();
    private lazy(){
     
        System.out.println("iiii");
    }
    private  static  lazy getLazy(){
     
        return lazy;
    }
  • 实验内容:网上这块说这个私有的对象,因为要在静态的方法里,返回给调用者,所以他是静态的,我觉得太牵强了。结合上面说的这个关键字给我的感觉,私有属性对象这句话,给我的感觉就像静态代码块,所以我做了一个小实验(原理不懂,如果大佬知道请明示)

  • 我首先没写返回这个对象的静态方法,我直接这么写的
    我发现,他也是执行构造函数的(预期之内),但是当我把static去掉的时候,构造函数就不执行了。所以说这个字感觉还是很有意思的

public class lazy {
     

   private  static lazy lazy=new lazy();
   private lazy(){
     
       System.out.println("iiii");
   }
 

JAVA–常见集合考点

集合是面试的重头,个人理解,后端嘛,那还是多跟数据打交道,其实集合就是不同的存储数据的方法。你要看的话,一看性能:查找的性能,增删的性能。二看,安全。两者平衡吧。
还得是机械键盘,速度这一块,来吧展示
首先大的方面有Collection与Map这两大接口,但是他们剥离的不是很彻底。set与map之间有很大的关系
转载一张图。
转载说明
https://www.cnblogs.com/bingyimeiling/p/10255037.html

Edgar校招后端学习--简历技术栈建立过程总结(持续更新)_第1张图片
看到这张图,队列那块我是不了解的。

常问的说下list set 与map

  • 首先说接口啊,list的话有序,可重复,就是说你插入的顺序就是他数据的顺序 set无序,不可重复。(这块真的有意思,你要到他们两的实现类里面去看,你就知道为啥了)hash的话是键值对这样的形式
  • 拿linklist举例,他是双向列表,默认头插法,所以链表的特性,增删比较快。arraylist的话底层是数组,查询自然快,有索引。但是增删就不好改了,你看到这也没说重复不重复咋回事,但是你能知道这两种的话都可以重复。
  • set的话,我们得知道hash算法,他们都计算hash值,(达到散列的目的)我们看两种hashset和treeset
  • hashset底层是Hashmap,hashmap不用说了,那是大头。
    1.8以后他把后面的链表做了点变换。这里先不说。set的话只是二叉树加数组,hashmap后面变成了红黑树。
  • treeset底层是红黑二叉树,我不太懂红黑二叉树。我先说说二叉树,二叉树的引用直接降低了层高,但是极限情况下,他会变成链表,所以说时间复杂度o(n)又上来了,怎么办–>上二叉平衡树,他能自旋,保持平衡状态,所以性能还是很好,是logn。但是这个自旋的时候,是要花时间的,所以我们产生了一种几乎平衡的树,红黑树。
  • 红黑树,加入了颜色属性,什么根节点和叶子加点都是黑的,红节点下面都是黑的。总之吧,他呢,最长路径不超过,最短路径的两倍是一种近乎于平衡的二叉树。
  • 在这说这么多,你去看其实hashmap的变化过程就是这样,从数组加链表到后来的数组加链表或者红黑二叉树这样一个过程。
  • 理解这些东西,要从基础的数据结构去理解不要死记硬背
  • 暂时要死记硬背的,hashmap 负载因子 0.75 链表长度到8的时候,变红黑树。红黑树到6的时候再变回来链表。
    线程安全问题
    1.Collections.synchronizedxxx都能解决上述集合并发安全问题
    2.要不你就用线程安全的类,比如说Hashtable,但是这个集合因为用sync修饰,他高并发的时候,效果不好。所以说你可以说用ConcurrentHashMap来代替。因为这个玩意是分段锁,没那么重。

Mysql相关知识

mysql的结构,两大部分
1.服务端,这里面控制大部分的服务.
2.插件式存储引擎(在Mysql 5.5 以后 innodb变成默认,常用的三种,innodb、Mysiam、memory)

一条查询语句要执行的流程

一条更新语句要执行的流程

说说mysql如何支持回滚(只有innodb支持事务)
两段式提交以及redo log 和 binlog
redo log顺序存储、binlog追加存储
先写到redo log里面,在一起提交

  • 怎样回滚

事务四大特性 常说的ACID–来自菜鸟教程
之前的理解很多被网上带偏了 请看下面菜鸟教程官方
1.原子性(atomic吧,我瞎说的啊),事务不可再拆分(现在暂时没有好的理解,就比如说转账这个业务,就是不能再拆分了,拆分以后,一方加钱,一方不动,那就不符合转账这个业务了,就是说对于这个业务不可再分。。?)
2.一致性:事务里面所有DML要么全部成功,要么全部失败。这事要么做成,要不不做,没有中间态。
3.隔离性:这个性质里面又有文章,简单说就是什么时候可见的性质。
4.持久性(想到了dao层。。取前一个字母D)
其实四大性质中,都是为了保证一个的一致性

自我理解
原子性就是:不成功便成仁!
一致性就是:假设说转账业务,原来双方一共有1000,你转完必须还是有1000,不能说凭空多了或者少了
隔离性就是:多事务并发执行中,你怎么定义你对某些数据的隔离性,说白了很像java里面的共享数据、或者加锁
持久性就是:就是一锤定音呗,写入了就是写入了。上午棱天地合,也不可能变了。

官方定义

  • 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

  • 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

  • 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

  • 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失

再说我们四大特性中最重要的隔离性前,看看并发访问数据库会出现什么情况

但是!隔离的越严实,效率越低!从上到下,效率越来越低!

什么是脏读、幻读、不可重复度

前提,你有两个并行执行的事务,他们之间一个是正常的DML操作,两一个就是执行select操作,下文我们定义查询操作叫我们的操作

脏读:你读到了人家还没提交的事务。这边人家确实dmlL 但是还未提交所以不符合逻辑。


幻读:幻读首先针对仅仅针对于Insert这种DML操作,我们本身的事务是统计行数的查询语句,前后行数不一致。 这有点跟下面的不可重复读差不多,只是幻读针对的是insert语句的查询,查询行数。


不可重复读:你读取前后数据不一致,假如说那边更新了下数据,我们的事务之前读的是1,后面人家改了以后,就是2了,最后你看下,唉?2!

后面查了一下官方定义也想了一下,不仅仅是insert啊,假如说delete删掉这一行呢,也会出现幻读的状况。幻读官方的定义就记住,前后查询的行数不一样。
另外,脏读是读取到人家没提交的,幻读和不可重复读是,你提交不提交我不管,我数据不一致。

事务隔离级别—四种
RU–RC–RR–SR
你别看是四种隔离级别对于我们JUC来讲,掐头去尾就剩两种。
第一种不要是因为,上面说的脏、幻、不可,他一个都没解决。。。
第四个不要是因为他压根直接把线程变成串行了。但是这块要明确一下,这是读写串行化,并不是完全意义上的串行化,只有读写这一步是串行的(当然效率依然很低)—其实我自己理解读写串行化对于数据库而言就是完全串行化了啊,数据库不就是读写吗?还干啥啊??但是他可能相对于整个完整的线程,这一部分是读写串行化的。

  • 读未提交:三种情况全部没解决。

  • 读提交(oracle数据库默认隔离级别)
    能避免脏读,但是对于不可重复度、幻读还是可能会出现。

  • 可重复读(mysql数据库隔离级别)
    幻读可能会出现;不可重复读、脏读解决。

  • 串行化
    串行化是隔离级别最高的,咱们之前说这些知识都是包括在JUC(并发编程)里面的。那你直接串行了,读写线程(读写串行!或者说线程中的读写部分)一个接一个走,老老实实的排队,当然不会出现幻读啊、脏读啊、不可重复读啊。
    下面有一个经典案例,两个事物纠缠在一块,看下v1、v2、v3的值
    RU因为是什么也没隔离:v1=20 v2=20 v3=20
    RC避免了脏读:v1=18 v2=20 v3=20
    RR在rc的基础上解决了不可重复读:v1=18 v2=18 v3=20
    ser串行不存在并发执行,那就得指定顺序了
    –此图来自享学课堂
    这个再往后是要学习LBCC以及MVCC就是如何实现底层隔离的!

到底什么是索引

  • 索引的的定义:是一种数据结构!是一种能实现快速查找的数据结构!是一种能够实现快速查找的、排好序的数据结构!
    但是不是仅有一种数据结构能实现索引。

先说下常见的数据结构
1.hash表–躲不过去的

  • 首先是hash算法,我学过的,取余算法(取出的余数相当于key),余数是多少就放在那一位。
  • 但是余数有相同的情况,然后就看你是开放数组方法(就是横着往后放)、多用的是开放链表法,相同的往数组节点下面的链表放。(所以你要重写equals方法,如果连values都相同那没必要往链表里面放了)。
    再说这个链表,jdk1.8后又升级了,因为你链表长度太长不利于查找了,变成动态的红黑树(链表长度大于8的时候)
  • 这个hash你要找一个两个很好找,你要是范围(区间)查询那效率就低了,因为他不是有序的,你得搜索整个hash数组。所以hash表适用于等值查询这种场景,你看这种结构,第一想起来的就是Nosql
    芒果数据库啊、或者是redis缓存这类的。
    2.相当熟悉的数组
  • 数组有索引,查询效率非常快(等值查询)。也能做范围查询,就一点不好,他的插入(删除同样)效率很低,你一插入后面的都得往后挪。。。。有一些固定数据不太变动的数据,你数组加上二分查找的话,o一下就变成log了,还是非常快的。
    3.树呢?二叉搜索树呢
    易混淆的点
    二叉树(基础)->二叉搜索树->(n叉树)b树->b+树(只在叶子节点放key)
    前提,下文说的是innodb引擎,不同引擎实现索引的数据结构也不一样。
  • 首先,二叉树家族很大很大(谢谢song哥的教育),二叉搜索树又叫二叉排序树,但是他不是动态平衡的,你一直做增删的话,这棵树可能会变成一个链表,那么搜索效率又下降了。。。。也就是左右层高的差没在1的范围内,而且只用二叉的话,层高会非常高,太多层高,会让很多节点直接打到硬盘上,我们知道磁盘的随机IO是最费时间的。
  • 这时候平衡树(b树)就要出场了,他是n叉的,这样层高就不会太高。这个哥们吧,他能自动调节左右层高,一直保持在1以内,就是形态的完整。最后出场的是b+树,b+树相比于b树就是,只有在叶子上存数据(存的是页(地址-页-页里面又有行)),这样的话其他非叶子节点能存储很多key,并且在叶子节点间加了相邻的指针,快速找到下一个节点。我们能让这个树更矮更胖,并且叶子节点间的遍历也更容易。
  • MyISAM 中的 B+ 树索引实现与 InnoDB 中的略有不同。在 MyISAM 中,B+ 树索引的叶子节点并不存储数据,而是存储数据的文件地址

下面这个博主说的非常全面了
https://www.cnblogs.com/zhuyeshen/p/12082839.html

索引模型–查找顺序–什么是回表

  • 聚簇索引与非聚簇索引
    就是一个是以主键为索引(聚簇索引),另一个不是(非聚簇索引)。(假设不创建主键也会有一个隐藏的主键)。
    两者的叶子节点也存着不同的数据,聚簇索引比较厉害,他的叶子存的是这行数据。而非聚簇叶子节点存的是主键的值。

  • 查询顺序是咋样的、什么叫回表
    查询顺序得看你是用那种索引了,聚簇还是非聚簇的。
    看到上面两种索引的机构我觉得你能感觉到,这两种查询区别很大,简单来说就是非聚簇查到以后,还要根据他叶子节点上主键的值,再回头查下’以聚簇为索引的这个b+树。上面这个过程叫回表


为什么自增主键是一个优化的选择

  • 自增主键,按顺序插入不会造成其他节点的挪动,不会造成页分裂,页合并。
  • 当然不是全部最优的,具体业务的时候,还要具体分析–引出雪花算法。因为业务的主键id并不一定是顺序增长的,,,你比如说身份证注册时候,同样会造成页分裂。。所以业务字段谨慎做主键。。

怎么减少回表

  • 覆盖索引
    简单说,查询的那列正好是主键(暂时理解),或者那列就直接在索引树上,当然不用回表。 下面语句id为主键,k为非聚簇索引,查到id就可以,不用回表。
    select ID from T where k between 3 and 5,
    我们上面说,如果那列直接就在索引树上可以。
  • 那我们不仅仅可以将主键放在索引树上啊。联合查询,先匹配第一个索引,再匹配第二个索引的时候,第二个索引就是我们要找的值得时候,我们就不用再回表了,直接拿走。
    联合索引 将另一个结果值也变成索引,减少回表

你可能感兴趣的:(后端面试,面试,并发编程,数据库)