广东网站制作哪家强,做网站的基本知识,网站建设 南宁,企业品牌策划与设计2026年即将来临#xff0c;很多同学会问Java面试八股文有必要背吗#xff1f;答案是#xff0c;必须背#xff0c;博主是个三本#xff0c;今年凭借这篇八股文斩获了多个大厂暑期实习offer#xff0c;相信秋招一定也可以发挥重要作用。你可以讨厌这种模式#xff0c;但你…2026年即将来临很多同学会问Java面试八股文有必要背吗答案是必须背博主是个三本今年凭借这篇八股文斩获了多个大厂暑期实习offer相信秋招一定也可以发挥重要作用。你可以讨厌这种模式但你一定要去背因为不背你就进不了大厂八股文能快速检验出求职者是否为科班出身专业基础强不强。国内的互联网面试恐怕是现存的、最接近科举考试的制度。我整理了一份 Java 基础篇的八股文大家在面试前可以背一遍一定能“吊打”面试官。另外可以关注博主博主主页有许多归类好的算法题目本篇是八股文中的八股文博主纯手打十分精炼每天背诵一个小时一个星期就能熟练背诵文章已整理成PDF需要全套面试笔记及答案可以在文末获取一、Java基础篇1.接口和抽象类的区别1抽象类可以有构造方法而接口没有2抽象类可以有抽象方法和具体方法接口只能有抽象方法3抽象类的成员4种权限修饰符都可以修饰接口只能用private2.重载和重写的区别重载发生在同一个类中方法名相同、参数列表、返回类型、权限修饰符可以不同重写发生在子类中方法名相、参数列表、返回类型都相同权限修饰符要大于父类方法声明异常范围要小于父类方法但是final和private修饰的方法不可重写3.和equals的区别比较基本类型比较的是值比较引用类型比较的是内存地址equlas是Object类的方法本质上与一样但是有些类重写了equals方法比如String的equals被重写后比较的是内存地址另外重写了equlas后也必须重写hashcode()方法4.异常处理机制1使用try、catch、finaly捕获异常finaly中的代码一定会执行捕获异常后程序会继续执行2使用throws声明该方法可能会抛出的异常类型出现异常后程序终止5.HashMap原理1.HashMap在Jdk1.8以后是基于数组链表红黑树来实现的特点是key不能重复可以为null线程不安全2.HashMap的扩容机制HashMap的默认容量为16默认的负载因子为0.75当HashMap中元素个数超过容量乘以负载因子的个数时就创建一个大小为前一次两倍的新数组再将原来数组中的数据复制到新数组中。当数组长度到达64且链表长度大于8时链表转为红黑树3.HashMap存取原理1计算key的hash值然后进行二次hash根据二次hash结果找到对应的索引位置2如果这个位置有值先进性equals比较若结果为true则取代该元素若结果为false就使用高低位平移法将节点插入链表JDK8以前使用头插法但是头插法在并发扩容时可能会造成环形链表或数据丢失而高低位平移发会发生数据覆盖的情况6.想要线程安全的HashMap怎么办1使用ConcurrentHashMap2使用HashTable3Collections.synchronizedHashMap()方法7.ConcurrentHashMap原如何保证的线程安全JDK1.7:使用分段锁将一个Map分为了16个段每个段都是一个小的hashmap每次操作只对其中一个段加锁JDK1.8:采用CASSynchronized保证线程安全每次插入数据时判断在当前数组下标是否是第一次插入是就通过CAS方式插入然后判断f.hash是否-1是的话就说明其他线程正在进行扩容当前线程也会参与扩容删除方法用了synchronized修饰保证并发下移除元素安全8.HashTable与HashMap的区别1HashTable的每个方法都用synchronized修饰因此是线程安全的但同时读写效率很低2HashTable的Key不允许为null3HashTable只对key进行一次hashHashMap进行了两次Hash4HashTable底层使用的数组加链表9.ArrayList和LinkedList的区别ArratList的底层使用动态数组默认容量为10当元素数量到达容量时生成一个新的数组大小为前一次的1.5倍然后将原来的数组copy过来因为数组有索引所以ArrayList查找数据更快但是添加数据效率更低LinkedList的底层使用链表在内存中是离散的没有扩容机制LinkedList在查找数据时需要从头遍历所以查找慢但是添加数据效率更高10.如何保证ArrayList的线程安全1使用collentions.synchronizedList方法为ArrayList加锁2使用VectorVector底层与Arraylist相同但是每个方法都由synchronized修饰速度很慢3使用juc下的CopyOnWriterArrayList该类实现了读操作不加锁写操作时为list创建一个副本期间其它线程读取的都是原本list写操作都在副本中进行写入完成后再将指针指向副本。11.String、StringBuffer、StringBuilder的区别String 由 char[] 数组构成使用了 final 修饰对 String 进行改变时每次都会新生成一个 String 对象然后把指针指向新的引用对象。StringBuffer可变并且线程安全StringBuiler不可变并且线程不安全。操作少量字符数据用 String单线程操作大量数据用 StringBuilder多线程操作大量数据用 StringBuffer二.Java多线程篇1.进程和线程的区别进程系统运行的基本单位包含多个线程线程独立运行的最小单位是进程的实体多个线程共享同一进程内的系统资源2. 什么是线程上下文切换当一个线程被剥夺cpu使用权时切换到另外一个线程执行3.什么是死锁死锁指多个线程在执行过程中因争夺资源造成的一种相互等待的僵局4.死锁的必要条件互斥条件同一资源同时只能由一个线程读取不可抢占条件不能强行剥夺线程占有的资源请求和保持条件请求其他资源的同时对自己手中的资源保持不放循环等待条件在相互等待资源的过程中形成一个闭环想要预防死锁只需要破坏其中一个条件即可银行家算法可以预防死锁5.Synchrpnized和lock的区别1synchronized是关键字lock是一个类2 synchronized在发生异常时会自动释放锁lock需要手动释放锁3synchronized是可重入锁、非公平锁、不可中断锁lock是可重入锁可中断锁可以是公平锁6.sleep()和wait()的区别(1)wait()是Object的方法sleep()是Thread类的方法(2)wait()会释放锁sleep()不会释放锁(3)wait()要在同步方法或者同步代码块中执行sleep()没有限制(4)wait()要调用notify()或notifyall()唤醒,sleep()自动唤醒7.yield()和join()区别yield()调用后线程进入就绪状态A线程中调用B线程的join() ,则B执行完前A进入阻塞状态8.线程池七大参数核心线程数线程池中的基本线程数量最大线程数当阻塞队列满了之后逐一启动最大线程的存活时间当阻塞队列的任务执行完后最大线长的回收时间最大线程的存活时间单位阻塞队列当核心线程满后后面来的任务都进入阻塞队列线程工厂用于生产线程任务拒绝策略阻塞队列满后拒绝任务有四种策略1抛异常2丢弃任务不抛异常3打回任务4尝试与最老的线程竞争9.Java内存模型JMMJava内存模型 屏蔽了各种硬件和操作系统的内存访问差异实现让Java程序在各平台下都能达到一致的内存访问效果它定义了JVM如何将程序中的变量在主存中读取具体定义为所有变量都存在主存中主存是线程共享区域每个线程都有自己独有的工作内存线程想要操作变量必须从主从中copy变量到自己的工作区每个线程的工作内存是相互隔离的由于主存与工作内存之间有读写延迟且读写不是原子性操作所以会有线程安全问题10.保证并发安全的三大特性原子性一次或多次操作在执行期间不被其他线程影响可见性当一个线程在工作内存修改了变量其他线程能立刻知道有序性JVM对指令的优化会让指令执行顺序改变有序性是禁止指令重排11.volatile保证变量的可见性和有序性不保证原子性。使用了 volatile 修饰变量后在变量修改后会立即同步到主存中每次用这个变量前会从主存刷新。单例模式双重校验锁变量为什么使用 volatile 修饰 禁止 JVM 指令重排序new Object()分为三个步骤申请内存空间将内存空间引用赋值给变量变量初始化。如果不禁止重排序有可能得到一个未经初始化的变量。12.线程使用方式(1)继承 Tread 类(2)实现 Runnable 接口(3)实现 Callable 接口带有返回值13.ThreadLocal原理原理是为每个线程创建变量副本不同线程之间不可见保证线程安全。每个线程内部都维护了一个Mapkey为threadLocal实例value为要保存的副本。但是使用ThreadLocal会存在内存泄露问题因为key为弱引用而value为强引用每次gc时key都会回收而value不会被回收。所以为了解决内存泄漏问题可以在每次使用完后删除value或者使用static修饰ThreadLocal可以随时获取value14.什么是CAS锁CAS锁可以保证原子性思想是更新内存时会判断内存值是否被别人修改过如果没有就直接更新。如果被修改就重新获取值直到更新完成为止。这样的缺点是1只能支持一个变量的原子操作不能保证整个代码块的原子操作2CAS频繁失败导致CPU开销大3ABS问题:线程1和线程2同时去修改一个变量将值从A改为B但线程1突然阻塞此时线程2将A改为B,然后线程3又将B改成A,此时线程1将A又改为B,这个过程线程2是不知道的这就是ABA问题可以通过版本号或时间戳解决15.Synchronized锁原理和优化Synchronize是通过对象头的markwordk来表明监视器的监视器本质是依赖操作系统的互斥锁实现的。操作系统实现线程切换要从用户态切换为核心态成本很高此时这种锁叫重量级锁在JDK1.6以后引入了偏向锁、轻量级锁、重量级锁偏向锁当一段代码没有别的线程访问此时线程去访问会直接获取偏向锁轻量级锁当锁是偏向锁时有另外一个线程来访问偏向锁会升级为轻量级锁这个线程会通过自旋方式不断获取锁不会阻塞提高性能重量级锁轻量级锁自旋一段时间后线程还没有获取到锁线程就会进入阻塞状态该锁会升级为重量级锁重量级锁时来竞争锁的所有线程都会阻塞性能降低注意锁只能升级不能降级16.JUC常用辅助类CountDownLatch:设定一个数当调用CountDown()时数量减一当调用await() 时判断计数器是否为0不为0就阻塞直到计数器为0CyclicBarrier设定一个数,当调用await() 时判断计数器是否达到目标值未达到就阻塞直到计数器达到目标值Semaphore:设定一个信号量当调用acquire()时判断是否还有信号有就信号量减一线程继续执行没有就阻塞等待其他线程释放信号量当调用release()时释放信号量唤醒阻塞线程17.如何根据 CPU 核心数设计线程池线程数量IO 密集型核心数*2计算密集型 核心数1为什么加 1即使当计算密集型的线程偶尔由于缺失故障或者其他原因而暂停时这个额外的线程也能确保 CPU 的时钟周期不会被浪费。三.JVM篇1.JVM运行时数据区内存结构线程私有区1虚拟机栈每次调用方法都会在虚拟机栈中产生一个栈帧每个栈帧中都有方法的参数、局部变量、方法出口等信息方法执行完毕后释放栈帧2本地方法栈为native修饰的本地方法提供的空间在HotSpot中与虚拟机合二为一3程序计数器保存指令执行的地址方便线程切回后能继续执行代码线程共享区4堆内存Jvm进行垃圾回收的主要区域存放对象信息分为新生代和老年代5方法区存放类信息、静态变量、常量、运行时常量池等信息。JDK1.8之前用持久代实现JDK1.8后用元空间实现元空间使用的是本地内存而非在JVM内存结构中2.什么情况下会内存溢出堆内存溢出1当对象一直创建而不被回收时2加载的类越来越多时3)虚拟机栈的线程越来越多时栈溢出方法调用次数过多一般是递归不当造成3.JVM有哪些垃圾回收算法1标记清除算法 标记不需要回收的对象然后清除没有标记的对象会造成许多内存碎片。2复制算法 将内存分为两块只使用一块进行垃圾回收时先将存活的对象复制到另一块区域然后清空之前的区域。用在新生代3标记整理算法 与标记清除算法类似但是在标记之后将存活对象向一端移动然后清除边界外的垃圾对象。用在老年代4.GC如何判断对象可以被回收1引用计数法已淘汰为每个对象添加引用计数器引用为0时判定可以回收会有两个对象相互引用无法回收的问题2可达性分析法从GCRoot开始往下搜索搜索过的路径称为引用链若一个对象GCRoot没有任何的引用链则判定可以回收GCRoot有虚拟机栈中引用的对象方法区中静态变量引用的对象本地方法栈中引用的对象5.典型垃圾回收器G1 JDK1.9以后的默认垃圾回收器支持并发采用标记整理复制算法注重响应速度6.类加载器和双亲委派机制从父类加载器到子类加载器分别为BootStrapClassLoader 加载路径为JAVA_HOME/jre/libExtensionClassLoader 加载路径为JAVA_HOME/jre/lib/extApplicationClassLoader 加载路径为classpath还有一个自定义类加载器当一个类加载器收到类加载请求时会先把这个请求交给父类加载器处理若父类加载器找不到该类再由自己去寻找。该机制可以避免类被重复加载还可以避免系统级别的类被篡改7.类加载过程1加载 加载字节码文件将字节码中的静态变量和常量转换到方法区中在堆中生成class对象作为方法区入口2连接验证验证字节码文件的正确性。准备正式为类变量在方法区中分配内存并设置初始值。解析将符号引用如类的全限定名解析为直接引用类在实际内存中的地址。3初始化 执行类构造器不是常规的构造方法为静态变量赋初值并初始化静态代码块。8.JVM中有哪些引用强引用new的对象。哪怕内存溢出也不会回收软引用只有内存不足时才会回收弱引用每次垃圾回收都会回收虚引用必须配合引用队列使用一般用于追踪垃圾回收动作9.对象头中有哪些信息对象头中有两部分一部分是MarkWork,存储对象运行时的数据如GC分代年龄、GC标记、锁的状态、线程ID等另外一部分是指向对象类型的指针如果是数组还有一个部分存放数组长度10.JVM内存参数-Xmx[]:堆空间最大内存-Xms[]:堆空间最小内存一般设置成跟堆空间最大内存一样的-Xmn[]:新生代的最大内存-xx[use 垃圾回收器名称]指定垃圾回收器-xss:设置单个线程栈大小一般设堆空间为最大可用物理地址的百分之8011.JVM类初始化顺序父类静态代码块和静态成员变量-子类静态代码块和静态成员变量-父类代码块和普通成员变量-父类构造方法-子类代码块和普成员变量-子类构造方法四.Mysql篇1.MyIAm和InnoDB的区别InnoDB支持事务MyIAm不支持InnoDB支持外键MyIAm不支持InnoDB是聚簇索引MyIAm是非聚簇索引InnoDB支持行锁和表锁MyIAm只支持表锁InnoDB不支持全文索引MyIAm支持InnoDB支持自增和MVCC模式的读写MyIAm不支持2.mysql事务特性原子性一个事务内的操作统一成功或失败一致性事务前后的数据总量不变隔离性事务与事务之间相互不影响持久性事务一旦提交发生的改变不可逆3.事务靠什么保证原子性由undolog日志保证他记录了需要回滚的日志信息回滚时撤销已执行的sql一致性由其他三大特性共同保证是事务的目的隔离性由MVCC保证持久性由redolog日志和内存保证mysql修改数据时内存和redolog会记录操作宕机时可恢复4.事务的隔离级别在高并发情况下并发事务会产生脏读、不可重复读、幻读问题这时需要用隔离级别来控制读未提交 允许一个事务读取另一个事务已提交的数据可能出现不可重复读幻读。读提交 只允许事务读取另一个事务没有提交的数据可能出现不可重复读幻读。可重复读 确保同一字段多次读取结果一致可能出现欢幻读。可串行化 所有事务逐次执行没有并发问日Inno DB 默认隔离级别为可重复读级别分为快照度和当前读并且通过间隙锁解决了幻读问题。5.什么是快照读和当前读*快照读读取的是当前数据的可见版本可能是会过期数据不加锁的select就是快照都*当前读读取的是数据的最新版本并且当前读返回的记录都会上锁保证其他事务不会并发修改这条记录。如update、insert、delete、select for undate排他锁、select lockin share mode共享锁 都是当前读6.MVCC是什么MVCC是多版本并发控制为每次事务生成一个新版本数据每个事务都由自己的版本从而不加锁就决绝读写冲突这种读叫做快照读。只在读已提交和可重复读中生效。实现原理由四个东西保证他们是undolog日志记录了数据历史版本readView:事务进行快照读时产生的视图记录了当前系统中活跃的事务id控制哪个历史版本对当前事务可见隐藏字段DB_TRC_ID 最近修改记录的事务ID隐藏字段DB_Roll_PTR 回滚指针配合undolog指向数据的上一个版本7.MySQL有哪些索引主键索引一张表只能有一个主键索引主键索引列不能有空值和重复值唯一索引唯一索引不能有相同值但允许为空普通索引允许出现重复值组合索引对多个字段建立一个联合索引减少索引开销遵循最左匹配原则全文索引myisam引擎支持通过建立倒排索引提升检索效率广泛用于搜索引擎8.聚簇索引和非聚簇索引的区别聚簇索引将索引和值放在了一起根据索引可以直接获取值如果主键值很大的话辅助索引也会变得很大非聚簇索引叶子节点存放的是数据行地址先根据索引找到数据地址再根据地址去找数据他们都是b数结构9.B和B数的区别为什么使用B数二叉树索引字段有序极端情况会变成链表形式AVL数树的高度不可控B数控制了树的高度但是索引值和data都分布在每个具体的节点当中若要进行范围查询要进行多次回溯IO开销大B树非叶子节点只存储索引值叶子节点再存储索引具体数据从小到大用链表连接在一起范围查询可直接遍历不需要回溯710.MySQL有哪些锁基于粒度*表级锁对整张表加锁粒度大并发小*行级锁对行加锁粒度小并发大*间隙锁间隙锁锁住表的一个区间间隙锁之间不会冲突只在可重复读下才生效解决了幻读基于属性*共享锁又称读锁一个事务为表加了读锁其它事务只能加读锁不能加写锁*排他锁又称写锁一个事务加写锁之后其他事务不能再加任何锁避免脏读问题11.MySQL如果做慢查询优化1分析sql语句是否加载了不需要的数据列2分析sql执行计划字段有没有索引索引是否失效是否用对索引3表中数据是否太大是不是要分库分表12.哪些情况索引会失效1where条件中有or除非所有查询条件都有索引否则失效2like查询用%开头索引失效3索引列参与计算索引失效4违背最左匹配原则索引失效5索引字段发生类型转换索引失效6mysql觉得全表扫描更快时数据少索引失效13.Mysql内连接、左连接、右连接的区别内连接取量表交集部分左连接取左表全部右表匹部分右连接取右表全部坐表匹部分五.Spring系列(spring全家桶)1.Bean 的作用域1Singleton:一个IOC容器只有一个2Prototype:每次调用getBean()都会生成一个新的对象3request:每个http请求都会创建一个自己的bean4session:同一个session共享一个实例5application:整个serverContext只有一个bean6webSocket:一个websocket只有一个bean2.Bean 生命周期实例化 Instantiation-属性赋值 Populate-初始化 Initialization-销毁 Destruction在这四步的基础上面Spring 提供了一些拓展点*Bean 自身的方法: 包括了 Bean 本身调用的方法和通过配置文件中的 init-method 和 destroy-method 指定的方法*Bean 级生命周期接口方法:包括了 BeanNameAware、BeanFactoryAware、InitializingBean 和 DiposableBean 这些接口的方法*容器级生命周期接口方法:包括了 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现一般称它们的实现类为“后处理器”。*工厂后处理器接口方法: 包括了 AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer 等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。3.Spring 事务原理spring事务有编程式和声明式我们一般使用声明式在某个方法上增加Transactional注解这个方法中的sql会统一成功或失败。原理是当一个方法加上Transactional注解spring会基于这个类生成一个代理对象并将这个代理对象作为bean当使用这个bean中的方法时如果存在Transactional注解就会将事务自动提交设为false然后执行方法执行过程没有异常则提交有异常则回滚、4.spring事务失效场景1事务方法所在的类没有加载到容器中2事务方法不是public类型3同一类中一个没有添加事务的方法调用另外以一个添加事务的方法事务不生效4spring事务默认只回滚运行时异常可以用rollbackfor属性设置5业务自己捕获了异常事务会认为程序正常秩序5.spring事务的隔离级别default:默认级别使用数据库自定义的隔离级别其它四种隔离级别与mysql一样6.spring事务的传播行为1支持当前事务如果不存在则新启一个事务2支持当前事务如果不存在则抛出异常3支持当前事务如果不存在则以非事务方式执行4不支持当前事务创建一个新事物5不支持当前事务如果已存在事务就抛异常6不支持当前事务始终以非事务方式执行7.Spring IoC8.spring用了哪些设计模式BeanFactory用了工厂模式AOP用了动态代理模式RestTemplate用来模板方法模式SpringMVC中handlerAdaper用来适配器模式Spring里的监听器用了观察者模式9.SpringMV工作原理SpringMVC工作过程围绕着前端控制器DispatchServerlet几个重要组件有HandleMapping处理器映射器、HandleAdapter处理器适配器、ViewReslover试图解析器工作流程1DispatchServerlet接收用户请求将请求发送给HandleMapping2HandleMapping根据请求url找到具体的handle和拦截器返回给DispatchServerlet3DispatchServerlet调用HandleAdapter,HandleAdapter执行具体的controller并将controller返回的ModelAndView返回给DispatchServler4DispatchServerlet将ModelAndView传给ViewReslover,ViewReslover解析后返回具体view5DispatchServerlet根据view进行视图渲染返回给用户10.springboot自动配置原理启动类SpringbootApplication注解下有三个关键注解1springbootConfiguration:表示启动类是一个自动配置类2CompontScan:扫描启动类所在包外的组件到容器中3EnableConfigutarion:最关键的一个注解他拥有两个子注解其中AutoConfigurationpackageu会将启动类所在包下的所有组件到容器中Import会导入一个自动配置文件选择器他会去加载META_INF目录下的spring.factories文件这个文件中存放很大自动配置类的全类名这些类会根据元注解的装配条件生效生效的类就会被实例化加载到ioc容器中11.springboot常用注解RestController 修饰类该控制器会返回Json数据RequestMapping(/path) 修饰类该控制器的请求路径Autowired : 修饰属性按照类型进行依赖注入PathVariable : 修饰参数将路径值映射到参数上ResponseBody :修饰方法该方法会返回Json数据RequestBody需要使用Post提交方式 :修饰参数将Json数据封装到对应参数中ControllerServiceCompont: 将类注册到ioc容器六.Redis系列1.redis为什么快1完全基于内存操作数据都存在内存中2采用单线程避免了不必要的上下文切换带来的性能问题也不用考虑锁的问题3基于非阻塞的io多路复用机制4数据结构简单对数据操作简单2.redis持久化机制1快照持久化RDBredis的默认持久化机制通过父进程fork一个子进程子进程将redis的数据快照写入一个临时文件等待持久化完毕后替换上一次的rdb文件。整个过程主进程不进行任何的io操作。持久化策略可以通过save配置单位时间内执行多少次操作触发持久化。所以RDB的优点是保证redis性能最大化恢复速度数据较快缺点是可能会丢失两次持久化之间的数据2追加持久化AOF以日志形式记录每一次的写入和删除操作策略有每秒同步、每次操作同步、不同步优点是数据完整性高缺点是运行效率低恢复时间长3.Redis如何实现key的过期删除采用的定期过期惰性过期定期删除 Redis 每隔一段时间从设置过期时间的 key 集合中随机抽取一些 key 检查是否过期如果已经过期做删除处理。惰性删除 Redis 在 key 被访问的时候检查 key 是否过期如果过期则删除。4.Redis数据类型String 常用命令 set,get,decr,incr,mget等Hash 常用命令 hget,hset,hgetall 等List 常用命令 lpush,rpush,lpop,rpop,lrange 等Set 常用命令 sadd,spop,smembers,sunion 等SortSet 常用命令 zadd,zrange,zrem,zcard 等5.Redis缓存穿透如何解决缓存穿透是指频繁请求客户端和缓存中都不存在的数据缓存永远不生效请求都到达了数据库。解决方案1在接口上做基础校验比如id0就拦截2缓存空对象找不到的数据也缓存起来并设置过期时间可能会造成短期不一致3布隆过滤器在客户端和缓存之间添加一个过滤器拦截掉一定不存在的数据请求6.Redis如何解决缓存击穿缓存击穿是值一个key非常热点key在某一瞬间失效导致大量请求到达数据库解决方案1设置热点数据永不过期2给缓存重建的业务加上互斥锁缺点是性能低7.Redis如何解决缓存雪崩缓存雪崩是值某一时间Key同时失效或redis宕机导致大量请求到达数据库解决方案1搭建集群保证高可用2进行数据预热给不同的key设置随机的过期时间3给缓存业务添加限流降级通过加锁或队列控制操作redis的线程数量4给业务添加多级缓存8.Redis分布式锁的实现原理原理是使用setnxsetex命令来实现但是会有一系列问题1任务时常超过缓存时间锁自动释放。可以使用Redision看门狗解决2加锁和释放锁的不是同一线程。可以在Value中存入uuid删除时进行验证。但是要注意验证锁和删除锁也不是一个原子性操作可以用lua脚本使之成为原子性操作3不可重入。可以使用Redision解决实现机制类似AQS,计数4redis集群下主节点宕机导致锁丢失。使用红锁解决9.Redis集群方案(1)主从模式个master节点多个slave节点master节点宕机slave自动变成主节点(2)哨兵模式在主从集群基础上添加哨兵节点或哨兵集群用于监控master节点健康状态通过投票机制选择slave成为主节点(3)分片集群主从模式和哨兵模式解决了并发读的问题但没有解决并发写的问题因此有了分片集群。分片集群有多个master节点并且不同master保存不同的数据master之间通过ping相互监测健康状态。客户端请求任意一个节点都会转发到正确节点因为每个master都被映射到0-16384个插槽上集群的key是根据key的hash值与插槽绑定10.Redis集群主从同步原理主从同步第一次是全量同步slave第一次请求master节点会根据replid判断是否是第一次同步是的话master会生成RDB发送给slave。后续为增量同步在发送RDB期间会产生一个缓存区间记录发送RDB期间产生的新的命令,slave节点在加载完后会持续读取缓存区间中的数据11.Redis缓存一致性解决方案更新数据库时把缓存给删除是最优方案可以更大概率避免并发问题但是依旧会有缓存删除失败的问题。可以使用分布式事务或者在删除失败后把key发送到rabbitMQ中进行异步删除重试七.计算机网络系列1.TCP/IP模型2.浏览器输入地址后做了什么3.TCP三次握手4.为什么TCP不能两次握手假设是两次握手若客户端发起的连接请求阻塞在网络中会造成该报文的重传这时服务收到连接请求后会立刻进入连接状态当双方传输完数据结束连接后第一次阻塞的请求突然又到达了服务端此时服务端又进入连接状态而客户端不会响应服务端的连接确认报文5.TCP四次挥手6.为什么要进入时间等待状态若客户端发送确认释放包后直接关闭而服务端因为某种原因没有收到客户端的确认释放包就会一直发送确认请求而客户端永远不会再响应该请求。7.TCP 滑动窗口TCP 流量控制主要使用滑动窗口协议滑动窗口是接受数据端使用的窗口大小用来告诉发送端接收端的缓存大小以此可以控制发送端发送数据的大小从而达到流量控制的目的。如果TCP发送方收到接收方的零窗口通知后会启动持续计时器。计时器超时后向接收方发送零窗口探测报文如果响应仍为0就重新计时不为0就打破死锁8.TCP拥塞控制发送方会维护一个拥塞窗口大小的状态变量大小取决于网络的拥塞程度。发送方的发送窗口大小是取接收方接收窗口和拥塞窗口中较小的一个拥塞控制有四种算法慢开始从小到大主键发送窗口每收到一个确认报文窗口大小指数增长拥塞避免当窗口大小到达一定阈值时转为拥塞避免每收到一个确认报文窗口大小1。若此时网络超时就把阈值调小一半重新慢开始快重传要求接收方收到请求后要立即回复快恢复发送方连续收到多个确认时就把拥塞避免阈值减小然后直接开始拥塞避免9.TCP超时重传发送方在发送按数据后一定时间内没有收到接收方响应报文就会重新发送刚刚的报文接收到收到报文后会对该报文的序列号进行检验已存在就抛弃10.TCP可靠传输的实现TCP是靠滑动窗口协议和连续ARQ协议配合流量控制和拥塞控制来保证的可靠传输。ARQ是停止等待协议和自动重传请求它规定TCP要为每一次传输的包编号每发送一个包要等待对方确认后才能发送下一个分组若一段时间对方没有确认就重新发送刚刚的报文。接收方会对数据包排序把有序数据传给应用层返回缺失的第一个ACK确认序列号给发送方,接收到收到报文后会对该报文的序列号进行检验重复就丢弃。流量控制是.....拥塞窗口上......上面已经说了11.TCP报头有哪些信息12.状态码1xx:请求正在处理2xx:请求成功处理3xx:请求重定向 301永久重定向 302临时重定向 304使用本地缓存4xx:客户端错误 400请求格式错误 403没有访问权限 404请求资源不存在5xx:服务端错误13.socket通信流程1服务端创建socket并调用bind()方法绑定ip和端口号2服务端调用listen()方法建立监听此时服务的scoket还没有打开3客户端创建socket并调用connect()方法像服务端请求连接4服务端socket监听到客户端请求后被动打开调用accept()方法接收客户端连接请求当accept()方法接收到客户端connect()方法返回的响应成功的信息后连接成功5客户端向socket写入请求信息服务端读取信息6客户端调用close()结束链接服务端监听到释放连接请求后也结束链接八.linux系列1.linux常用命令ifconfig:查看网络接口详情ping查看与某主机是否能联通ps -ef|grep 进程名称查看进程号lost -i 端口 查看端口占用情况top:查看系统负载情况包括系统时间、系统所有进程状态、cpu情况free:查看内存占用情况kill:正常杀死进程发出的信号可能会被阻塞kill -9:强制杀死进程发送的是exit命令不会被阻塞2.linux的io模型IO是数据的读取和写入用户进程读取一次IO请求分为两个阶段等待数据到达内核缓冲区和将内核空间数据拷贝到进程空间当用户去内核中拷贝数据时要从用户态转为核心态5中io模型:(1)同步阻塞IO模型用户进程发起io调用后会被阻塞等待内核数据准备完毕时就被唤醒将内核数据复制到用户进程。这两个阶段都是阻塞的(2)同步非阻塞IO模型用户进程发起IO调用后若内核数据还未准备好进程不会被阻塞,而是给用户进程返回一个error进程会继续干别的事每隔一段时间就去看看内核数据是否准备好。不过将内核数据复制到用户进程这个阶段依旧是阻塞的(3)IO多路复用模型同步非阻塞IO要不停的查看内核中数据是否准备好十分消耗cpu。IO多路复用让一个线程去监控一个fd文件每个用户进程都有一个fd文件描述符将自己的文件描述符写入这个fd文件当某个用户进程需要的数据准备好后这个线程就去通知用户进程。(4)信号IO模型当用户进程发起IO调用后会向内核注册一个信号处理函数进程不会被阻塞当内核数据准备就绪时就返回一个信号给用户进程进程就可以直接在这个信号处理函数中获取内核数据进行拷贝。拷贝这个阶段依旧是阻塞的5异步非阻塞模型前面四种全是同步的。进程在发起IO调用后无论数据是否到达都直接返回结果。内核数据准备好时由内核将数据复制给用户进程。两个阶段都是非阻塞的九.其他RabitMQ、数据结构与算法、nginx、git、jwtd登录等...篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题需要全套面试笔记及答案可以点击下方名片获取