Java基本语法回顾总结

dengliang356a / 2023-07-07 / 原文

(1)hashcode()、equals()[相关:4]

1.如果hashcode()不相同,两个对象一定不是同一个对象
2.如果hashcode()相同,两个对象不一定上同一个对象,需要进一步判别equals
3.如果equals相同,应当认为两个对象就是相同对象
由于hashcode方法仅返回一个值,equals里面有若干逻辑,因此,部分集合类的判断中,会优先判断hashcode,如果相同再继续equals判断
结论:如果改写了equals方法,则必须改写hashcode方法,以便于逻辑一致

(2)string、stringbuffer、stringbuilder

string:常量,每次修改都会创建新的字符串常量
stringbuffer:线程安全的字符串变量
stringbuilder:不安全的字符串变量

(3)extends、super

<? extends T>:?是T的子类
<? super T>:?是T的基类

(4)== 、 equals

==:基本类型-看值;引用类型-看引用地址
euqals:看各种类的重写逻辑[逻辑里面也有可能复用==]

(5)重载、重写

重载:针对单一类中,相同方法名,不同方法签名
重写:针对父子类,相同方法名,相同方法签名
重写:返回值类型、抛出异常都必须小于等于父类;访问修饰符大于等于父类

(6)list、set

list:有序,可重复,允许多个null,支持下标随机访问
set:无序,不可重复,单一null,必须遍历访问

(7)arraylist、linkedlist

arraylist:基于数组实现,有利于查找、修改,不利于插入、删除[适用场景不同]
linkedlist:基于链表实现,有利于插入、删除,不利于查找、修改[适用场景不同]

(8)concurrenthashmap扩容机理

1.7之前:基于segment分段hashmap存储实现的,segment分段存储部分不扩容,仅内部的hashmap进行扩容[哪个线程对应的内部hashmap需要扩容,哪个线程就负责做这个事情]
1.8之后:不是基于segment分段存储实现的,所有的K-V对都包含在一个map中,只是扩容的时候,那就每个子线程都参与扩容

(9)JDK版本变迁,hashmap的主要变更

1.7:底层是数组+链表,哈希算法复杂
1.8:底层是数组+链表+红黑树,由于引入红黑树,哈希算法得到简化,从而优化hashmap的插入、查询效率

(10)hashmap的put方法

大体流程:
1.依据key和哈希算法计算下标
2.如果下标位置为空,则封装成对象(1.7:entry对象,1.8:node对象),放置该位置
3.如果下标位置不空,
3.1 JDK1.7:判断是否需要扩容,然后,头插法插入到对应位置的链表中
3.2 JDK.8:判断是红黑树节点还是链表节点,然后插入到hashmap里面,最后判断扩容
3.2.1 红黑树节点:将KV对封装成红黑树节点,加入到红黑树中
3.2.2 链表节点:尾插法插入到对应位置的链表中,如果多于等于8个节点,将链表转为红黑树

(11)深拷贝与浅拷贝

浅拷贝:基本数据类型拷贝了第二份,引用类型的变量全部都是拷贝了一份引用地址,指向了原来的地方。
深拷贝:所有数据类型都拷贝了第二份,不仅仅拷贝引用地址。

(12)hashmap扩容机理

1.7:生成新数组,遍历原数组上的每个链表,将内部数据逐个转移至新数组
1.8:生成新数组,遍历原数组上的每个链表与红黑树
①如果原数组上是链表,遍历每个元素,重新计算下标并转移
②如果原数组上是红黑树,遍历每个元素,重新计算下标并转移,有冲突再购建链表与红黑树

(13)copyonwriteArrayList

线程安全的arrayList,底层也是用数组实现的,主要集中在读与写操作上
读:由于读写分别在老新数组上,因此,互相不干扰,也因此,读的性能不会受写的性能影响[适用于读多写少]
写:写操作会生成新数组,在完成之前,其他线程无法进行写操作[上了锁,线程安全];在完成之前,读的是原数组,写的是新数组,两者是不会互相干扰的。

(14)字节码

定义:字节码文件是Java源码编译过后的一种格式,各个平台上相同的源码编译出的字节码是相同的,但是,字节码转化的机器码不相同,这个转化上JDK(JRE)做的,因此,Java上跨平台语言
相当于编译过程所指的,中间代码[前有词法分析、语法分析、语义分析][后有代码优化、目标代码生成]
优点:实现了语言的跨平台;编译过程可以做代码优化,提高执行效率

(15)Java异常体系

graph TD; Throwable --> Exception Throwable --> Error Exception --> RuntimeException Exception --> 非RuntimeException

error是非常严重的错误,程序已无法正常运行,没必要捕获
运行时异常,一般是逻辑问题,应尽量避免
非运行时异常,不处理无法正常运行,必须处理

(16)什么时候抛异常?什么时候捕获异常?
抛:自身无法处理就往上抛,由上级处理
捕获:自身能处理就捕获,捕获走既定处理流程

(17)类加载器

graph TD; bootstrapClassLoader负责加载JAVA_HOME下lib里面的jar包与类文件 --> ExtClassLoader负责加载JAVA_HOME下lib下ext里面的jar包与类文件 --> AppClassLoader负责加载classpath路径下的类文件

(18)类加载器的双亲委派模型

由16可知,类加载器共三个,AppClassLoader有两个父类
当AppClassLoader加载时,会优先调用父类的加载器,这种JVM机制叫做双亲委派模型
AppClassLoader.loadClass(){
  ExtClassLoader.loadClass(){
    bootstrapClassLoader.loadClass();
  }
}

(19)线程共享区

堆区与方法区是所有线程共享的
栈区:主要存放基本数据类型与对象引用(仅限局部变量,成员变量不管是不是基本数据类型都存放于堆)
堆区:主要存放对象实例与数组[我的理解就是,由代码操作生成的对象或者说引用类型存放于堆]
方法区:类信息(class文件)、静态变量与静态方法
本地方法栈:非静态方法

(20)如何排查JVM问题-※
空间:jmap 查看 JVM各个区域的占用情况,查看是否栈区过大?是否堆区过大?
时间:jstack 查看线程的运行情况,是否存在死锁或者阻塞?

OOM:
查看: jstat 查看垃圾回收情况,fullgc 与 younggc 的运行情况
记录: JVM启动参数 --> -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/base,发生OOM的时候记录下当时的情况-dump文件,便于回溯定位问题
分析:jvisualvm 可以针对dump文件进行分析异常对象,异常线程

(21)从加载JVM到GC清理,一共经历什么过程-√
1.方法区加载字节码,加载静态方法、静态成员变量
2.堆区创建实例化对象,保存至 年轻代 Eden 区
3.将引用传回栈区
4.经过minor GC,对象每次存活,年龄加一,并迁移至survival区-存活区,年龄大于等于15的时候,对象进入老年代
5.栈区的引用被移除以后,对象最终被GC回收

(22)如何确定对象是否需要回收
根可达算法:所有对象都是基于一个根对象上的,从根对象开始遍历,能找到引用的就是还需要的对象,否则就是不需要的对象。

(23)JVM垃圾回收机制
总共三种算法:
标记:将所有对象判断是否根可达,将不可达对象标记并进行删除
缺点:会有碎片空间出现

复制法:申请一块与当前存储空间相同的空间,根可达算法标记所有存活对象,将存活对象迁移至新申请空间,迁移完毕以后,原空间统一清空
缺点:需要的空间较大

标记优化法:根可达算法标记所有存活对象,并将存活对象重新排列至连续空间,标记以及迁移排列完毕以后,将存活对象连续空间以外的空间统一清除

(24)什么是STW
STW,stop the world,即,在GC运行过程中,要将所有Java进程冻结,以便于GC进程进行垃圾回收。

参考:

  1. https://blog.csdn.net/liwenxiang629/article/details/109508530
  2. https://blog.csdn.net/weixin_43235210/article/details/90444710?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-90444710-blog-109508530.235%5Ev38%5Epc_relevant_sort&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-90444710-blog-109508530.235%5Ev38%5Epc_relevant_sort&utm_relevant_index=2
  1. 常用的JVM启动参数有哪些?-※
  2. 线程安全的理解?
  3. 线程安全说的是,当多个线程并发访问互斥资源时,读写互斥资源的代码逻辑能正常处理,获得正确结果,不会互相干扰的情况。
  4. 守护线程的理解?
  5. 守护线程是与普通线程相区分的概念,用户一般使用的就是普通线程,普通线程有自身独立的生命周期,而守护线程的生命周期取决于普通线程,只有当所有相关的普通线程都结束时,守护线程才会结束。 守护线程是为所有普通线程提供服务的线程
  6. threadlocal的底层原理
  7. threadlocal:在线程里面多保存了一份map结构,由于变量存在线程内部,从而保证不同线程互相不干扰。 现在大多数用的都是线程池,由于线程都是复用的,而threadlocal往线程里面添加了一个map,因此,需要代码里面手动回收移除threadlocal保存的数据,否则,线程一直复用,数据量会一直累加至OOM。
  8. 并发、并行与串行之间的区别?
  9. 并行:多条处理流同时执行,例如多端口同时工作,多条线路同时传送数据 串行:多条处理流排队执行。 并发:例如微机系统上有多个进程存活,从宏观上,多个进程上同时工作,是个并行的流程,但是,从微观底层上来看,多个进程是由CPU通过时间片轮转,逐个调度执行的,是个串行的流程,这个就是并发。
  10. Java死锁应如何避免?-√
  11. Java死锁由四个因素导致:
    • 资源是互斥资源 每次仅可由单个线程持有
    • 在获得所有资源之前,线程自身不释放已持有资源
    • 所需资源在其他线程上,且不可被剥夺
    • 循环依赖,A持有B所需资源,B持有A所需资源
    应当打破第四点因素,即可避免死锁发生。 即将所有线程持有资源的顺序固定,避免产生循环依赖 每个锁的持有时间应当设置过期时间,确保锁最终一定会被释放
  12. 线程池底层工作原理-√
  13. num:线程数量 当有任务需求时, 当numpoolSize时,且queue没满时,将任务添加到队列中排队 当maxpoolsize>num>poolSize时,且queue已满时,增加线程处理任务 当maxpoolsize==num,且queue已满时,不再新增线程,会按照handler所指定策略处理新任务。 同时会检查,是否有线程的空闲时间大于keepalivetime,如果有,终止对应线程
  14. 线程池中阻塞队列的作用?线程池为何先添加队列而不是先创建线程-√
  15. 阻塞队列可以通过阻塞保留那些想要入队的任务;阻塞队列自带阻塞和唤醒功能,不需要一直占有CPU资源。 因为创建新线程需要获取全局锁,影响其他线程的效率,且线程数量不足有可能是临时性不足,因此,优先排队等待。
  16. ReentrantLock中的公平锁与非公平锁的底层实现-※
  17. 加锁[竞争锁]: 公平锁:新线程直接进入到队列 非公平锁:先直接竞争锁,竞争不到再进入队列

    唤醒:无论公平锁还是非公平锁都会直接唤醒队列第一个获取锁

  18. ReentrantLock的tryLock()与lock()区别
  19. tryLock()可能加锁成功[返回真],也可能加锁不成功[返回假],非阻塞加锁 lock()阻塞性加锁,一直执行,直到加锁成功
  20. CountDownLatch与Semphore的区别和底层原理-※
  21. sychronized的偏向锁、轻量锁以及重量锁
  22. sychronized语法,某个线程持有锁的时候,锁就已经是偏向锁 当某个线程持有锁,且有其他线程也在等待锁释放,锁就升级为轻量锁 某个线程持有锁,其他线程会自旋尝试获取锁,自旋次数达到一定程度,线程仍然没有获取到锁时,轻量锁就升级为重量锁
  1. ReentrantLock与synchronized的区别?-√
  2. 含义:ReentrantLock是一个类;synchronized是一个关键字
    是否公平:ReentrantLock可以加公平锁,也可以加非公平锁;synchronized只能是非公平锁。
    synchronized自动加锁释放锁,ReentrantLock需要手动加锁释放锁
    synchronized是JVM层面的锁,ReentrantLock是API层面的锁
    
  3. 对AQS的理解,AQS如何实现可重入锁-※
  4. AQS是一个用于JAVA线程同步的框架。
    AQS内部维护了一个状态变量state和一个线程双向队列。
    在可重入锁的场景下,state表示加锁次数,当state减少至0时,代表持有锁的线程释放锁了,就唤醒下一个线程竞争锁。
    
  5. 对IOC的理解
  6. inverse of control,控制翻转,将bean的生成交给spring管理,例如,@autowired自动装配的mapper层对象。
    好处:单例bean可以有效复用,减少对象生成的时间成本。各种bean还有自身的应用场景。
    
  7. 单例bean与单例模式
  8. spring自动装配出来的对象全都会指向同一个单例bean,不强制约束用户不可创建第二个对象。
    单例模式针对的是类而言的,如果某个类应用了单例模式,那么这个类就不可能创建出第二个对象,所有该类的引用都会指向同一个对象,不管是spring自动装配还是用户自己new。
    
  9. spring事务传播机制-※
  10. spring事务什么时候会失效-√
  11. 数据库:数据库如果不支持事务,那么spring事务就会失效
    Java:
    类:事务所在类没有对应的注解,spring没有在容器里面生成该类的bean[类上面没有component之类的注解]
    方法:方法上没有加上事务注解或者方法的权限修饰符不是public
    调用:调用方法没有使用代理对象,而是通过原对象调用的方法。[自己new]
    
  12. spring中创建的bean,生命周期有哪些-※
  13. 1.推断构造方法
    2.实例化
    3.依赖注入[构造方法可能需要部分外部注入属性;成员变量中依赖于其他类,等等多种需要将其他实例注入的情况]
    4.处理@postConstruct注解,构造之后还可以执行的自定义处理
    5.处理initializingBean接口复写内容,如果实现了该接口的话[前面就是bean的实例化,这一步就是bean的初始化,这就是两者的区别]
    6.生成代理对象,最后生成bean
    
  14. spring中的bean是线程安全的吗?
  15. 如果bean上有状态,就不是线程安全的
    如果bean上没有状态,就是线程安全的
  16. applicationContext和beanFactory有什么区别?
  17. beanFatory的功能,applicationContext都有,但applicationContext还有其他功能[获取系统环境变量、事件发布]
  18. spring中的事务是如何实现的?-※
  19. @Transactional什么时候会失效?
  20. 类:事务所在类没有对应的注解,spring没有在容器里面生成该类的bean
    方法:方法上没有加上事务注解或者方法的权限修饰符不是公共的
    调用:调用方法没有使用代理对象,而是通过原对象调用的方法。
    
  21. spring容器的启动流程是怎样的?-※
  22. 1.扫描所有beanDefinition对象,并保存至map
    2.筛选出单例bean进行bean创建,推断构造方法-实例化-依赖注入-postConstruct注解-beanInition接口复写方法-生成代理对象-生成bean
    3.applicationContext发布spring容器启动事件
    
  1. spring用到了哪些设计模式?
  2. 1.beanFactory-工厂模式
    2.单例bean-单例模式
    3.代理对象-代理模式
    
  3. spring boot常用注解及其底层实现-※
  4. 常用注解有
    1.@bean 方法级注解,可用于对应的单例bean对象
    2.@autowired 用于生成单例bean的引用;要求原类增加类注解例如component\service\controller\mapper等来交给spring托管
    3.@controller\@service\@mapper,这三都是类注解,用于指定controller、service、mapper类,从而可以自动将请求匹配到controller对应方法上,以及自动调用对应的SQL
    4.@GetMapping,@PostMapping,用于指定请求的匹配类型,方法接收get请求、post请求等等
    
    具体实现 不太清楚
    
  5. springboot是如何启动Tomcat?
  6. 1.检索是否有tomcat依赖
    2.将tomcat实例化,并加入到spring容器中
    3.启动tomcat实例
    
  7. mybatis的优缺点-※
  8. 优点:
    1.SQL写在XML里面,与业务代码分离,因此相对比较灵活,便于统一管理
    2.spring集成很方便,由于使用的JDBC连接数据库,因此,不需要针对不同数据专门做兼容
    
    缺点:
    SQL的编写,SQL的语法都强关联数据库的类型,因此,无法随意切换数据库
    
    
  9. mybatis中#{}和${}的区别?
  10. # 的作用是占位符,将Java里面的变量按类型注入进来,可以有效防止SQL注入
    $ 的作用是替换,不能防SQL注入,会在传递到数据库之前,就将内容直接文本替换到对应的位置,可以用于SQL语句不确定的场景[或者说可变]
    
  11. 索引的基本原理-√
  12. 1.索引对应列进行排序
    2.将排序结果建立倒排表
    3.将数据地址链拼接到倒排表上
    4.查询的时候,拿到倒排表,查询到数据地址链,最后取到需要的数据
    
  13. 索引的设计原则
  14. 1.类型不多的列没必要建索引,占空间,效果还不好
    2.由于索引也是要占空间的,而且索引建立完毕以后,之后的写入操作都需要更新索引,因此,索引越多对写入操作越不友好,索引的数量要控制
    3.索引建立的列,不能是全模糊和前模糊查询的那种情况[全模糊与前模糊都不走索引],尽量建立在精确匹配的场景
    4.索引建立的列,尽量不要建立在text类型上
    
  15. 事务的基本特性和隔离级别-※
  16. 基本特性
    ACID: atom consistent isolation duration
    原子性:每个事务的执行应当是原子性的,要么都执行,要么都不执行
    一致性:数据库总是从一致性的状态变化到另外一种一致性的状态,所有数据应当具有一致的状态,不存在矛盾;即无论何时,数据都应当满足本身的约束条件    
    隔离性:事务之间应当是隔离的,不会互相影响
    持久性:事务一旦提交,就持久化到数据库里面了
    
    隔离级别
    1.读未提交 脏读,一个事务A没有执行完,另一个事务B读到了A的中间处理结果
    2.读已提交 不可重复读,一个事务A没有执行完,事务B读到的数据为C,事务A执行完毕,事务B读到的数据为D
    3.可重复读 ,利用多版本并发控制,事务A写操作的数据版本与事务B读操作的数据版本不一致,从而保证两个事务读写操作是独立的
    4.串行,每个操作都加锁,保证串行执行,但效率很低,一般不用
    
    
  17. 什么是MVCC
  18. MVCC multi version concurrent control 多版本并发控制
    
    简而言之就是 每个数据都有若干版本,读写分离,操作的是不同版本的数据
    
    读已提交:每次读 都生成一个readView
    可重复读:每次读都复用同一个readView
    
    
  19. 简述MyISAM和InnoDB的区别-※
  20. Explain语句中各个字段分别表示什么?-※
  21. 索引覆盖是什么?
  22. 查询索引的时候,所有目标结果列就已经包含在索引里面了,因此,就没有必要再去查找原表了,从而提高了查询效率
    
  1. 最左前缀原则是什么?-※
  2. 查询SQL的时候,如果利用到了联合索引,那么使用的顺序与建立索引的顺序必须保持一致
    
  3. InnoDB是如何实现事务的?-※
  4. B树和B+树的区别?为什么Mysql使用B+树?-※
  5. Mysql的锁有哪些?如何理解?-√
  6. 1.共享锁 排他锁
    共享锁:其他线程可以读 但是不能写,也不能加排他锁,可以加共享锁
    排他锁:其他线程不可读不可写,也不能继续加锁
    
    2.行锁 表锁
    行锁:锁定一行
    表锁:锁定一张表
    
    3.乐观锁、悲观锁
    乐观锁:不是真正上锁 而是通过数据多版本控制的方式实现上锁,乐观认为 自己上锁以后 不会有其他线程同时访问修改该数据,最后判断一下上锁的版本号是不是最新的版本,如果不是最新版本就放弃操作
    悲观锁:例如行锁、表锁
    
    
  7. 什么是RDB和AOF?-√
  8. RDB:保存redis某个时刻快照的文件,可以用于redis全量同步,或者持久化
    
    优点:
    1.仅一个dump.rdb,方便持久化
    2.方便容灾备份
    3.恢复性能比AOF好
    
    缺点:
    1.由于是全量快照,因此,只能一段时间持久化一次。那就有可能存在,这段时间数据丢失的风险
    2.由于是全量快照,因此,如果数据量较大的时候,可能会比较耗时。
    
    AOF:保存redis一段时间内的操作日志,可以用于redis增量同步,或者持久化
    
    优点:
    1.AOF保存比RDB保存会更频繁,因此,就算丢失,丢失的改动也会少很多,甚至如果选择每修改同步的策略的话,那么最多就丢失一条操作指令
    
    缺点:
    1.恢复起来比RDB方式要慢,即性能是比不上RDB的
    2.AOF文件比RDB文件要大
    
  9. Redis的过期键删除策略?
  10. 定时过期:每隔一段时间,将redis所有过期键删除[CPU-难过 内存-友好]
    
    惰性过期:当且仅当用到的时候判断是否过期,过期就删除[CPU-友好 内存-难过]
    
    定期过期:另外两种策略的折中,每隔一段时间就触发一次,每次都去遍历过期键删除,但是,这个过程有限时,超过一定时间就恢复redis正常使用
    
  11. 简述redis的事务实现?
  12. 首先得从下面几个关键字开始说,
    multi、exec、discard、watch
    
    multi:开始一个事务
    
    命令入队列:这个阶段输入要执行的命令
    
    exec与discard命令输入,代表事务的结束,redis就开始执行整个事务或者抛弃整个事务
    
    watch:给整个事务加乐观锁 如果监听的数据被别人改动了,那么整体事务回滚
    
  13. redis主从复制的核心原理?-√
  14. 核心就是 主节点成功以后,就直接返回,然后才同步到从节点,因此,存在不一致的风险[ZK则是先保证一致性 再返回给调用方]
    
    两种复制同步内容:
    全量同步:
    1.将主节点上的所有数据保存一份快照,bgsave持久化RDB文件
    2.将文件传递给从节点,全量同步到从节点[阻塞]
    
    增量同步:
    1.增量同步的前提,需要维护一份偏移量和一个缓冲队列
    2.在缓冲队列没有满到溢出的情况下,从节点将同步请求发给主节点[里面带上运行ID]
    2.1 第一次连接[运行ID不相同],主节点将运行ID传回给从节点,并进行全量RDB同步,从节点保存当前主节点的运行ID
    2.2 非初次连接[运行ID相同],那么就只需要将缓冲队列中改动同步到从节点即可
    
    


  15. Redis有哪些数据结构?分别有哪些经典应用场景?-※
  16. Redis分布式锁底层是如何实现的?-√
  17. 核心 就是利用lua脚本的原子性
    
    1.setnx 保证当且仅当 没有其他线程设置这个key的时候 才往里写数据上锁
    2.最后一定要将自己上的锁给释放掉
    3.用try保证出异常的时候,最后一定会释放锁
    4.确保释放的锁是自己加的
    5.每把锁都必须设置过期时间,以确保不会出现某个线程一直持有锁
    6.要额外一个线程进行锁续命
    
    服务端 向redis主节点请求锁
    主节点锁请求成功,返回给服务端
    然后将状态同步到从节点
    
    
  18. redis集群策略?
  19. redis共三种模式
    
    主从模式:主节点挂了可以访问从节点
    哨兵模式:增加部分节点,设为哨兵,监视主节点状态,主节点挂了以后,从节点重新选举出主节点[单主多从]
    集群模式:多主多从,同样会自动选举出新-主节点
    
    
  20. 缓存穿透、缓存刺穿、缓存雪崩
  21. 缓存雪崩: 多个key在redis中不存在,且有很多请求同时访问这些数据,导致数据库压力较大,常见于服务端刚起,缓存内无数据
    处理:
    1.缓存预热,请求访问之前,预先查询一遍,将部分key的内容保存至缓存
    2.互斥锁,执行SQL的部分上锁,同样的请求,仅放第一个执行SQL,后续全部走redis
    3.热点数据,缓存过期时间稍微设置偏差一点,防止一批数据同时过期失效
    
    缓存穿透:请求访问的是,缓存和数据库都没有的数据[有可能不是合法数据],当key没有的时候,就会去查询数据库,但同时,又没有合法数据会存入redis,导致如果利用这种请求,做重放攻击的话,就会导致数据库浪费很多性能
    处理:
    1.可以枚举所有情况的场景下,利用布隆过滤器可以筛选掉部分请求,就不让请求走到业务逻辑
    2.无法枚举的情况下,请求还是正常走业务逻辑,只是,查询数据库没有数据的情况下,直接往redis里面存放null等提前预设的空值,等下一次请求判断redis的时候,获取到该值即可直接判断,无需再查数据库。
    
    缓存刺穿:某个key过期了,导致请求一直走到数据库,且有很多请求同时访问这个数据[热点数据]
    处理:
    1.互斥锁,key过期以后,同一个key的查询请求,有且仅有一个请求能进入查询SQL的流程,SQL查询完毕就保存redis,其余都直接查询redis
    
    

参考:
1.https://www.jb51.net/article/280467.htm
2.https://baijiahao.baidu.com/s?id=1767052815720228275&wfr=spider&for=pc

  1. redis与MySQL如何保持数据一致?
  2. 1.删除redis缓存
    2.更新MySQL
    3.删除redis缓存
    
  3. redis的持久化机制
  4. 两种持久化命令:
    save:阻塞性持久化,会阻塞redis主进程,直到持久化完成
    bgsave:非阻塞性持久化,通过新建子线程专门持久化,从而不影响redis主进程
    
    手动就是上面两种命令
    自动就是save M N ,相当于设置一个定时器,定时备份持久化的感觉[非阻塞持久化]
    
    两种持久化格式
    RDB:redis某个时刻的快照
    优点:
    1.仅一个RDB文件,方便持久化与备份
    2.方便恢复,性能较好
    
    缺点:
    1.有可能丢数据,因为记录的是某个时刻的状态,因此,记录时刻与同步时刻之间的这段时间改动是有可能丢失的
    2.数据多的时候,持久化的速度会比AOF慢
    
    AOF:记录命令的操作日志
    优点:
    1.持久化可以设置每修改同步,即每次改动都记录操作日志,因此,最理想的情况,仅丢失一条改动
    2.持久化的速度会更快
    缺点:
    1.恢复性能不如RDB,会更慢,启动速度也会更慢
    2.文件整体会比RDB更大
    
  5. redis单线程为什么这么快-※
  6. 简述redis事务实现
  7. 1.multi开始事务
    2.命令入队
    3.exec 或 discard ,执行事务 或者 放弃事务
    4.watch在multi之前输入,用于给事务加上乐观锁
    
  8. CAP理论与BASE理论-√
  9. CAP: consistent && avaliable && partition tolerance
    一致性:整个系统的数据状态应该是一致的,不存在逻辑矛盾的
    可用性:整个系统应该保证是可用的
    分区容错性:整个系统应当有容灾性能,有哪个节点失效或者哪个服务挂掉了,也要保证系统的基本可用
    一般是保证AP 或者 CP
    
    BASE:basic avaliable && soft state && eventually consistent
    基本可用:即,允许系统有一定程度的不可用,例如,请求时间变长 或者 非核心功能 暂时不可用
    软状态:允许系统短期不一致,即系统处于某种中间状态
    最终一致性:经过一段时间,整个系统最终能达到数据状态一致的情况
    
  10. 什么是RPC
  11. RPC remote process call 远程过程调用
    与编程语言、运行环境等其他东西都无关
    它可以利用http,也可以利用tcp
    
  12. 数据一致性模型有哪些-√
  13. 强一致:每次修改过后,系统就已经做到数据一致,没有逻辑冲突矛盾
    弱一致:每次修改以后,不承诺可以读到修改后的数据,也不承诺多久之后可以达到数据一致的状态
    最终一致:过一段时间以后,系统最终能达到数据一致的状态
    
  14. 分布式ID是什么?有哪些解决方案
  15. 在分布式部署的情况下,全局唯一ID,称之为分布式ID
    0.UUID生成,能搞定,但是需要额外的空间与性能,且不直观
    1.数据库统一维护,每次请求ID都向同一个数据库请求,数据库负责自增
    2.redis等存储中间件,每次请求ID都向redis请求,redis负责自增
    3.雪花算法[1+41+10+12][不用+时间+主机号+进程号]
    
  16. 分布式锁的应用场景是什么?有哪些实现方案?
  17. 多个分布式部署的后台进程同时操作互斥资源,需要分布式锁,才能保证数据一致,处理逻辑正常
    
    1.ZK实现 侧重CP
    2.redis实现 侧重AP
    
    redis的分布式锁,有可能出现主从不同步的风险,解决方案是红锁,但是官方都不推荐使用这个
    
    成熟的用法:redisson
    
    具体的注意事项:
    1.setnx 当且仅当key不存在的时候,才上锁,否则就上锁失败
    2.处理逻辑最后要移除锁
    3.异常处理
    4.判断锁归属
    5.锁超时
    6.锁续命
    
  18. 什么是ZAB协议-※
  19. ZAB协议是保证ZK一致性的原子广播协议
    ZK实现一致性共三个阶段:
    1.选举leader:因为只有leader节点处理写操作
    2.数据同步:所有follower要与leader保持数据一致性
    3.请求广播:收到写请求的时候,会将写请求广播到所有follower节点,从而尽量使得所有节点的写操作是同时处理的
    
    
  20. 为什么ZK可以用来做注册中心-√
  21. 1. ZK可以保存对应的key-value
    2. ZK的watch机制可以做服务发现
    3. ZK底层用的多线程模型,性能也还行
    ZK可以监控每个服务的连接情况,从而通报给监控的节点,从而更新对应的服务URL
    
  22. ZK的leader领导选举流程是怎样的
  23. 核心是投票选举
    所有follower
    1.首先投票给自己
    2.两两PK,赢家不做操作,输家将票改投赢家,或者赢家的赢家。
    3.如果PK是平局,则票还是投给自己
    4.PK结束,输家将票数情况传给下一个PK对象
    5.如果有节点PK赢过一半以上的节点,则直接被选为leader
    
    
  1. ZK节点数据是如何同步的[或者说同步流程有哪些?]
  2. 1.集群启动时,首先选举出leader节点
    2.leader节点收到写请求
    -------------日志持久化-----------------------
    3.leader将日志发送给follower
    4.follower日志持久化成功以后,返回ACK确认给leader
    ---------------内存更新-----------------------
    5.leader收到半数以上的ACK以后,leader更新内存数据
    6.将commit指令发送给从节点
    ---------------返回客户端------------------------------
    7.leader节点返回响应成功
    
    
    
    
  3. dubbo负载均衡策略?
  4. 1.随机:随机分配
    2.轮询:循环遍历
    3.源地址哈希:每个请求都计算哈希值,相同的请求计算出相同的哈希值,就会分配到相同的服务
    
  5. dubbo如何服务导出
  6. dubbo如何服务引入
  7. dubbo架构设计是怎样的?
  8. 负载均衡算法有哪些
  9. 1.随机:随机分配
    2.轮询:循环遍历
    3.源地址哈希:每个请求都计算哈希值,相同的请求计算出相同的哈希值,就会分配到相同的服务
    4.加权随机:部分服务的权重增加,随机到的次数就更多
    5.加权轮询:部分服务的权重增加,遍历的时候,多访问几次
    
  10. 分布式架构,session有哪些方案
  11. 所谓的session共享,一般是在分布式多服务的场景下探讨的。由于后台服务较多,且因为负载均衡的原因,每次访问的后台可能不是同一个服务,因此,一些临时信息需要在不同服务之间共享[例如登录信息]
    
    1.客户端保留,比如,存在cookies里面,由前端每次带入;存在浏览器localstorage;存在vuex
    2.存入Redis等存储中间件
    3.后台若干服务做同步[感觉要开发较长时间还不稳定]
    
    
  12. 如何实现接口幂等性
  13. 所谓的幂等性,指的是,相同的请求,发一次和发多次,效果应当是稳定一致的。
    就请求类型而言,
    删除、查询
    1.通过请求里面带的ID,或者请求参数拼接计算出一个ID,将ID存入Redis等存储中间件,用ID来标识请求是否处理过
    修改、新增
    2.除了阻断请求到数据库处理以外,还可以通过在数据库处理的时候,加上乐观锁,保证如果有其他请求修改的话,就放弃修改
    
  14. 简述ZK的命名服务、配置管理与集群管理
  15. 命名服务:通过某个名字获得对应的URL等配置,由于ZK可以保存类似的KV对,将key设为名字即可获得对应的URL
    配置管理:将服务地址等多个多个配置,保存到ZK的节点中。配置改动以后,ZK通过watch机制可以通知到其他服务
    集群管理:减少服务或者服务不可用时,ZK连接断开以后,watch机制也能将服务改动通知到其他服务
    
  16. ZK的watch机制
  17. 实体:


    客户端线程
    客户端watchManage
    ZK

    消息:

    消息次数:


    每个watch监听仅生效一次,每次通知过后,监听器会被移除,需要重新注册

    消息内容:


    仅通知事件本身,不通知事件内容

    流程:


    1.客户端向ZK注册watch监听器
    2.ZK返回监听器相关信息,并存入客户端watchManage
    3.ZK监听到变化,客户端调用watcher对象的回调方法
  18. ZK和euraka的区别
  19. 存储拆分以后,如何保证唯一主键[解决方案应当与分布式ID的解决方案相同]
  20. 0.UUID
    1.单数据库自增ID
    2.Redis存储中级件
    3.雪花算法
    
  1. 雪花算法原理
  2. 1+41+10+12
    不用+时间+机器ID+进程ID
    
  3. spring cloud 常用组件及其作用
  4. 如何避免缓存雪崩、缓存穿透、缓存刺穿
  5. 缓存雪崩:
    1.缓存预热
    2.互斥锁
    3.过期岔开
    
    缓存刺穿:
    1.缓存预热
    2.互斥锁
    
    缓存穿透:
    1.能枚举:布隆过滤器,做请求拦截
    2.不能枚举:互斥锁,设置Null,将后续请求拦截到数据库处理之外
    
  6. 分布式系统中常用的缓存方案
  7. 1.客户端:localstorage、vuex
    2.nginx:静态资源
    3.Java:内存缓存
    4.Redis:存储中间件
    5.操作系统缓存
    6.数据库缓存:mybatis分页组件利用了
    
  8. 缓存过期策略
  9. 定时过期
    惰性过期
    定期过期
    
  10. 常见的缓存淘汰算法
  11. FIFO:先进先出
    LRU:最近最少使用
    LFU:一段时间,最少使用
    
  12. 布隆过滤器原理及优缺点
  13. 原理
    存
    1.每个key通过若干哈希算法,得到对应下标
    2.对应下标的位置全部置为1
    取
    3.给定key计算对应下标,如果都为1,可能在里面,有0,肯定不在里面
    
    优点:
    1.占用空间小
    2.速度快,耗时少,O(K),K为哈希算法数量
    
    缺点:
    1.仅能判断在或不在,拿不到原值
    2.存在假阳性误判情况
    
  14. 分布式缓存寻址算法
  15. 哈希:点对点
    一致性哈希:点对段
    哈希slot:还是点对段,但是,由于增加了逻辑层,可以减小节点上下线的开销
    
  16. spring cloud 和 dubbo有哪些区别
  17. 什么是服务雪崩和服务限流
  18. 服务雪崩:
    服务之间存在调用关系,A-->B-->C,当C的并发量超出最大能力时,C阻塞 导致 B阻塞,最终导致 A阻塞,这个称之为服务雪崩
    服务限流:
    为了避免超出服务的最大承受能力,控制服务接收的请求数量,称之为服务限流
    
  19. 什么是服务熔断和服务降级
  20. 服务熔断
    服务之间存在调用关系,A-->B-->C,当C服务不可用或者阻塞时,B服务不再去调用C,而是直接返回,这个称之为服务熔断
    服务降级
    由于异常情况,将部分服务停掉或者限流,这个称之为服务降级
    
  21. SOA、分布式、微服务,什么关系与区别
  22. 分布式,指的是服务部署在多台服务器上,一般微服务都是分布式部署
    SOA主要是针对服务而言的,主要是指所有服务都挂载到总线上的一种架构
    微服务主要是针对服务而言的,将系统功能拆分为互相不重叠的微服务,通过各种微服务的互相调用来完成业务功能
    
  1. 怎么拆分微服务
  2. 1.按照功能划分,各个微服务的功能应当没有重叠
    2.微服务不能绕过对方的接口去访问数据
    
  3. DDD领域驱动设计-※
  4. 什么是中台
  5. 所谓中台,就是将可复用功能,形成公共组件[CSP人像服务]
    代码公共组件:业务中台
    数据公共组件:数据中台
    
  6. 项目怎么保证敏捷开发
  7. 1.会议
    2.文档
    3.持续构建
    4.持续集成
    
  8. 消息队列选型-√
  9. kafka:
    优点:吞吐量高,性能高
    缺点:功能单一,有丢失消息的风险
    
    rocketMQ:
    优点:功能完善,性能好
    缺点:客户端仅支持Java
    
  10. RocketMQ事务消息实现-※
  11. ZK为什么能作为注册中心
  12. 1. ZK可以保存对应的key-value
    2. ZK的watch机制可以做服务发现
    3. ZK底层用的多线程模型,性能也还行
    ZK可以监控每个服务的连接情况,从而通报给监控的节点,从而更新对应的服务URL
    
  13. RocketMQ底层实现原理-※
  14. 消息队列如何保证可靠传输
  15. 可靠传输:不能多 不能少
    1.消费者实现幂等性,哪怕多收消息,也能保证逻辑正常
    2.关闭自动提交,收发消息都要收到ACK确认
    
  16. 消息队列的作用
  17. 本身独立:    各功能解耦
    收发异步:    缓冲、削峰
    下游能处理:  异步通信
    下游不能处理:健壮性
    
  18. 死信队列和延时队列是什么
  19. 死信队列:没有成功消费的消息,可以用于消息重试
    延时队列:隔一段时间才发送消息,可以用于限时操作之类的判断
    
  20. 如何保证消息的高速读写
  21. 核心在于零拷贝
    
  22. epoll和poll的区别-※
  23. TCP三次握手和四次挥手
  24. A请求连接B
    B发送ACK给A
    A发送ACK给B
    
    A请求断开连接B
    B发送ACK给A[已确认收到请求,但是还需要等待B空闲]
    B发送断连请求给A[B空闲才发断连请求]
    A发送ACK给B
    
  25. 浏览器一个请求到一个响应,经历的步骤
  26. 1.请求URL,通过DNS解析找到对应IP以及端口
    2.NGINX之类反向代理到对应的服务上
    3.后台服务依据URL,将请求转发至对应的类,对应的接口上
    4.接口走完所有逻辑以后,返回响应
    5.客户端收到响应后渲染
    
  27. 跨域请求是什么,有什么问题,怎么解决
  28. 客户端发起请求时,会检查请求的协议、域名、端口是否与当前一致,如果不一致就会出现跨域问题
    要处理该问题:
    1.请求:请求通过后台转发至真正的接口[夹一层转发层,利用后台转发,类似网关]
    2.响应:响应上面加上“access-control-allow-origin”
    
  29. 零拷贝是什么-※
  30. 零拷贝的定义在于 一块区域的数据需要迁移的时候,不再需要拷贝至用户空间,而是直接在内核空间完成操作
    核心在于两种方式:mmap  transfile[DMA方式]
    
    mmap:原本文件要拷贝至应用层,mmap则取消这个步骤,仅将数据映射引入到用户空间,数据本身不拷贝至用户空间
    transfile[sendfile]:数据映射都不引入用户空间,直接使用DMA,将数据在内核之中,直接写入到socket缓冲区,缓冲区直接迁移至目标区域
    
    两者区别:sendfile方式比mmap少了两次上下文切换