八股+面经

文章目录

  • 项目介绍
    • 1.不动产项目
      • 数据
      • 机器学习算法调研
      • 图像提取算法调研
        • 数据集-ImageNet
        • Xception
        • VGG
        • Inception
        • Densenet
        • Mobilenet
    • 2.图书项目
      • 技术栈
      • 面试问题
  • Java基础
    • Map
      • HashMap v.s Hashtable(5点)
      • ConcurrentHashMap v.s Hashtable(2点)
      • 代理模式
        • 1. 静态代理
        • 2. 动态代理
        • 2.1 JDK 动态代理机制
        • 2.2 CGLIB 动态代理机制
  • Java并发
    • 并发编程三个重要特性
    • 线程
    • volatile
      • 如何保证变量的可见性?
      • 如何禁止指令重排序?
      • volatile 可以保证原子性么?
    • synchronized
      • 1. 使用场景
      • 2. 底层原理
        • synchronized 同步语句块
        • synchronized 修饰方法
      • 3. 和volatile区别
    • ReentrantLock
        • 和synchronized区别
    • 线程池
      • 1. 线程池作用
      • 2. 创建线程池方法
      • 3. 线程池饱和策略
      • 4. 常用阻塞队列
      • 5. 线程池处理任务流程
      • 6. 线程池大小
  • JVM
    • 类加载机制
    • 垃圾回收(GC)
      • 1. 引用类型
      • 2. 垃圾收集
      • 3. 垃圾回收算法(内存回收方法论)
      • 4. 垃圾收集器(内存回收具体实现)
        • **Serial:**
        • **ParNew:**
        • **Parallel Scavenge:**
        • **Serial Old**
        • **Parallel Old**
        • **CMS**
        • **G1**(Garbage-First)
        • 总结
  • 设计模式
    • 单例模式
  • MySQL
    • 存储引擎
    • 索引
      • 1. 优缺点
      • 2. 底层数据结构
        • B&B+树
      • 3. 索引类型总结
    • 事务
      • 1. ACID
      • 2. 并发事务问题
      • 3. 并发事务控制方式
        • MVCC
      • 4. 隔离级别
    • 锁机制
    • MVCC
      • RC和RR下 MVCC 的差异
  • Redis
    • 为什么用redis做mysql缓存?
    • 数据结构
        • 常见数据结构
        • 底层数据结构
    • 线程模型
        • 1. 单线程模式
        • 2. 单线程 v.s 多线程
    • 缓存读写策略
      • 1. 旁路缓存模式
      • 2. 读写穿透
      • 3. 异步缓存写入
  • 计算机网络
    • HTTP与HTTPS
    • 三次握手(建立TCP连接)
    • 四次挥手(断开TCP连接)
    • TCP v.s UDP
  • 操作系统
  • Spring
    • IoC
    • AoP
  • 面试题目
    • 拼多多 3.23
    • 美团-履约 3.24
    • 联想 3.27
    • 蚂蚁-数金 3.28
    • 美团-酒旅 3.30

项目介绍

1.不动产项目

八股+面经_第1张图片

数据

机器学习算法调研

12种基学习器,评价指标为RMSE、MAE、MAPE和R2,最终选定Catboost和LightGBM

image-20230404160403504

图像提取算法调研

数据集-ImageNet

Xception

论文:Xception: Deep Learning with Depthwise Separable Convolutions (CVPR 2017)

源码:Keras开源代码

VGG

Very Deep Convolutional Networks for Large-Scale Image Recognition

Inception

Densenet

Mobilenet

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LSXqaK4S-1681986884287)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20230419190536360.png)]

2.图书项目

JPA和Mybatis区别

技术栈

前端服务器Nginx后端服务器Tomcat,开发前端内容时,可以把前端的请求通过前端服务器转发给后端(称为反向代理

八股+面经_第2张图片

用户信息明文存储在数据库中,不安全

shiro

三大概念

  • Subject:负责存储与修改当前用户的信息和状态
  • SecurityManager:安全相关的操作实际上是由她管理的
  • Realms:负责从数据源中获取数据并加工后传给 SecurityManager

四大功能

  • Authentication(认证)
  • Authorization(授权)
  • Session Management(会话管理)
  • Cryptography(加密)

面试问题

  1. Spring Security和Shiro的区别?

    • Shiro比Spring更容易使用,实现和理解
    • Shiro 功能强大、且 简单、灵活
    • Shiro是 Apache 下的项目,比较可靠,不跟任何的框架或者容器绑定,可以独立运行
  2. 项目中redis用什么客户端部署?

    • Java 访问 Redis 主要是通过 JedisLettuce 两种由不同团队开发的客户端(提供访问、操作所需的 API),Jedis 比较原生,Lettuce 提供的能力更加全面

    • 本项目用Spring Data Redis,Spring Data Redis是在 Lettuce 的基础上做了一些封装,与 Spring 生态更加贴合,使用起来也更简便。

延时双删:先清除缓存,在更新数据库后,等一段时间,再去第二次执行删除操作。

Java基础

Map

HashMap v.s Hashtable(5点)

八股+面经_第3张图片

ConcurrentHashMap v.s Hashtable(2点)

  1. 底层数据结构不同
八股+面经_第4张图片
  1. 实现线程安全方式不同
八股+面经_第5张图片

代理模式

1. 静态代理

2. 动态代理

  • 2.1 JDK 动态代理机制

  • 2.2 CGLIB 动态代理机制

Java并发

并发编程三个重要特性

  1. 原子性

    Java实现:synchronized 、各种 Lock 以及各种原子类

    synchronized 和各种 Lock 可以保证任一时刻只有一个线程访问该代码块,因此可以保障原子性。各种原子类是利用 CAS (compare and swap) 操作(可能也会用到 volatile或者final关键字)来保证原子操作。

  2. 可见性

    含义:一个线程对共享变量进行修改,另外的线程立即可以看到修改后的最新值。

    Java实现:synchronizedvolatile 以及各种 Lock

  3. 有序性

    含义:代码的执行顺序未必就是编写代码时候的顺序。

    Java实现:volatile 关键字可以禁止指令进行重排序优化

线程

  • 什么是线程?
    • 比进程更小的执行单位
    • 线程切换工作时负担比进程小得多
  • 进程和线程的区别
    • 八股+面经_第6张图片
    • 进程可以有多个线程,同类的多个线程共享进程的方法区资源,每个线程有自己的程序计数器、虚拟机栈本地方法栈
    • 各进程是独立的,同一进程中的线程可能会互相影响
    • 线程执行开销小,但不利于资源的管理和保护;进程相反
  • 为啥程序计数器是私有的?
    • 为了线程切换后能恢复到正确的执行位置
  • 为啥虚拟机栈和本地方法栈私有?
    • 为了保证线程中的局部变量不被别的线程访问到
  • 堆和方法区了解
    • 堆是进程中最大的一块内存,主要用于存放新创建的对象

volatile

  • 如何保证变量的可见性?

    • 用 **volatile**关键字
    • 如果我们将变量声明为 volatile ,这就指示 JVM,这个变量是共享且不稳定的,每次使用它都到主存中进行读取。
    • volatile 关键字能保证数据的可见性,但不能保证数据的原子性。synchronized 关键字两者都能保证。
  • 如何禁止指令重排序?

    • 用 **volatile**关键字

    • 如果我们将变量声明为 volatile ,在对这个变量进行读写操作的时候,会通过插入特定的 内存屏障 的方式来禁止指令重排序。

    • volatile使用场景:双重校验锁实现对象单例(线程安全)

      • public class Singleton {
        
            private volatile static Singleton uniqueInstance;//volatile修饰!
            
            private Singleton() {}
            
            public  static Singleton getUniqueInstance() {
                if (uniqueInstance == null) {//没有实例化过才进入加锁代码
                    synchronized (Singleton.class) {//类对象加锁
                        if (uniqueInstance == null) {
                            /*这句话分三步进行:
                            1.为 uniqueInstance 分配内存空间
                            2.初始化 uniqueInstance
                            3.将 uniqueInstance 指向分配的内存地址
                            JVM指令重排,可能变成1->3->2,因此需要volatile*/
                            uniqueInstance = new Singleton();
                        }
                    }
                }
                return uniqueInstance;
            }
        }
        
  • volatile 可以保证原子性么?

    • 不能,只能保证可见性和有序性
    • 怎么改进?
      • synchronizedLock或者AtomicInteger

synchronized

synchronized主要解决的是多个线程之间访问资源的同步性,可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行

1. 使用场景

  • 1. 修饰实例方法(锁当前对象实例)

    • synchronized void method() {
          //业务代码
      }
      
  • 2. 修饰静态方法(锁当前类)

    • synchronized static void method() {
          //业务代码
      }
      
  • 3. 修饰代码块(锁指定对象/类)

    • synchronized(this) {
          //业务代码
      }
      
  • 注意:构造方法不能用synchronized修饰!(构造方法本身就线程安全)

2. 底层原理

底层依赖于JVM

  • synchronized 同步语句块

    • synchronized 同步语句块的实现使用的是 monitorentermonitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。

    • 在执行**monitorenter**时,会尝试获取对象的锁,如果锁的计数器为 0 则表示锁可以被获取,获取后将锁计数器设为 1 也就是加 1。

    • 八股+面经_第7张图片
    • 对象锁的的拥有者线程才可以执行 monitorexit 指令来释放锁。在执行 monitorexit 指令后,将锁计数器设为 0,表明锁被释放,其他线程可以尝试获取锁。

    • 八股+面经_第8张图片
    • 如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外一个线程释放为止。

  • synchronized 修饰方法

    • synchronized 修饰的方法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是 ACC_SYNCHRONIZED 标识,该标识指明了该方法是一个同步方法。JVM 通过该 ACC_SYNCHRONIZED 访问标志来辨别一个方法是否声明为同步方法,从而执行相应的同步调用。

    • 如果是实例方法,JVM 会尝试获取实例对象的锁。如果是静态方法,JVM 会尝试获取当前 class 的锁。

  • 同步语句块用monitorenter 指令和 monitorexit 指令,修饰方法用**ACC_SYNCHRONIZED** 标识,不过两者的本质都是对对象监视器 monitor 的获取

3. 和volatile区别

synchronizedvolatile是互补的存在,区别有四点:

  • 性能volatile 关键字是线程同步的轻量级实现,性能比synchronized好
  • 使用volatile 只能用于变量,synchronized 可以修饰方法以及代码块
  • 并发特性volatile能保证数据的可见性,但不能保证数据的原子性。synchronized 关键字两者都能保证
  • 场景volatile主要用于解决变量在多个线程之间的可见性,而 synchronized 关键字解决的是多个线程之间访问资源的同步性

ReentrantLock

  • ReentrantLock 实现了 Lock 接口,是一个可重入独占式的锁
  • 底层:AQS(AbstractQueuedSynchronizer
    • ReentrantLock 里面有一个内部类 SyncSync 继承 AQS,添加锁和释放锁的大部分操作实际上都是在 Sync 中实现的
    • Sync 有公平锁 FairSync 和非公平锁 NonfairSync 两个子类
      • 公平锁:先等待的线程先获得锁
      • 非公平锁:随机线程获得锁,性能更好,但可能某些线程永远无法获得锁(ReentrantLock 默认)

八股+面经_第9张图片

和synchronized区别

  • 都是可重入锁
    • 可重入锁也叫递归锁,指的是线程可以再次获取自己的内部锁
    • JDK所有现成的Lock实现类,包括synchronized 关键字锁都是可重入的
  • 依赖对象不同
    • synchronized 依赖于 JVM
    • ReentrantLock 依赖于 API(需要lock()和unlock()方法配合try/finally语句块完成)
  • ReentrantLock功能更多
    • ReentrantLock增加了三点高级功能:
      • 等待可中断:正在等待的线程可以选择放弃等待,处理其他事情
        • 可中断锁:获取锁的过程可以被中断,进行其他逻辑处理【ReentrantLock】
        • 不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理【synchronized】
      • 可实现公平锁
        • ReentrantLock可以指定是公平锁还是非公平锁(默认非公平)
        • synchronized只能是非公平锁
      • 可实现选择性通知(锁可以绑定多个条件)
        • synchronized关键字与wait()notify()/notifyAll()方法相结合可以实现等待/通知机制
        • ReentrantLock类需要借助于Condition接口与newCondition()方法实现

线程池

线程池就是管理一系列线程的资源池,有任务处理->线程池拿线程->处理完不销毁->线程等待下一个任务

1. 线程池作用

提供限制和管理资源的方式 && 维护一些基本统计信息

  • **降低资源消耗。**重复利用已创建的线程降低创建销毁的消耗。
  • **提高响应速度。**任务到达时,任务不需要等到线程创建就能立即执行。
  • **提高线程可管理性。**线程池统一分配、调优和监控线程。

2. 创建线程池方法

  1. ThreadPoolExecutor构造函数
  2. Executor 框架的工具类 Executors

3. 线程池饱和策略

线程达到最大数量,队列也被放满了任务,ThreadPoolExecutor.定义的策略:

  1. .AbortPolicy:抛出异常拒绝新任务的处理。
  2. .CallerRunsPolicy:调用自己的线程运行任务。
  3. .DiscardPolicy:不处理新任务,直接丢弃。
  4. .DiscardOldestPolicy:丢弃最老未处理的任务请求。

4. 常用阻塞队列

新任务到来->当前运行线程数==核心线程数?->√->新任务放队列

不同线程池用不同的阻塞队列

  1. LinkedBlockingQueue(无界队列):队列永远不会被放满
  2. SynchronousQueue(同步队列):没有容量,不存储元素。
  3. DelayedWorkQueue(延迟阻塞队列):内部采用“堆”

5. 线程池处理任务流程

八股+面经_第10张图片

6. 线程池大小

  • 太大->增加上下文切换成本

  • 太小->大量请求/任务堆积

  • CPU密集型任务(N+1):线程数设置为 N(CPU核心数)+1

  • I/O密集型任务(2N)

JVM

类加载机制

  • 类加载器:通过类的全限定性类名(带包路径,如java.lang.String)获取该类的二进制字节流
    • Bootstrap:加载java核心库(如$JAVA_HOME/jre/lib/rt.jar)
      • 好处:不需要太多的安全检查,提升性能
    • Extension:加载拓展库($JAVA_HOME/jre/lib/ext/*.jar)
    • AppClass:根据java的类路径加载类,一般的java应用的类($CLASSPATH)
    • 用户自定义:
  • 加载方式:双亲委派机制
    • 过程:
      • 收到类加载请求,不会自己加载,而是逐级向上委托,最终到达顶层的Bootstrap;
      • 如果父类加载器完成,则返回;否则,交给子类尝试。
    • 好处:
      • 避免类的重复加载:java类由于加载机制,形成了优先级的层次关系
      • 防止核心类被篡改:防止下层的同名类篡改核心API库
    • 打破这个机制
      • 意义:由于类加载器受到加载范围的限制,某些情况下父类加载器无法加载需要的类(不属于其加载范围,但根据机制只能其加载),所以需要子类加载器加载。
      • 方法:使用自定义加载器
      • 如何:
        • 1、找到ClassLoader类的loadClass()方法,拷贝
        • 2、写自定义加载器类,粘贴
        • 3、删去loadClass()中的双亲委派机制的部分
        • 4、判断类是否为系统类,是的话使用双亲委派机制,否则自己的方法加载。
      • 应用:
        • Tomcat:webappClassLoader加载自己目录下的class文件,目的;1、隔离每个webapp下的class和lib;2、使用单独的加载器以免被恶意破坏;3、热部署(修改文件不用重启自动重新装载)

垃圾回收(GC)

1. 引用类型

八股+面经_第11张图片

2. 垃圾收集

  • 垃圾:不再被使用的对象,死亡的对象

  • 哪些垃圾需要回收?

    • 引用计数法:每个对象添加一个引用计数器,当为0时,就表示死亡;

      • 问题:循环引用,不可回收造成内存泄露;空间占用
    • 可达性分析算法:以根对象集合(GC Roots)为起点,分析GC Roots连接的对象是否可达,解决了循环引用问题。

      八股+面经_第12张图片
      • GC Roots:就是对象!

        • 1、虚拟机栈中的栈帧中的局部变量所引用的对象;
        • 2、java本地方法栈中(java本地接口)引用的对象;
        • 3、方法区中静态变量引用的对象;(全局对象)
        • 4、方法区中常量引用的对象(全局对象)
      • 问题:多线程下更新了访问过的对象的引用

        • 误报:原被引用的对象不再被引用。影响较小,顶多减少GC次数。

        • 漏报:将已被访问过的对象设置为未被访问过。影响较大,可能会使引用对象被GC,导致jvm崩溃。

          • 解决方法:Stop-the-world,等所有线程到达安全点,再进行Stop-the-world。
            • Stop-the-world:用户运行至安全点(safe point)或者安全区域之后,就会挂起,进入暂停状态。
  • 什么时候回收?

    • Minor GC:young gc,发生在年轻代的gc
    • Major GC:olg gc,发生在老年代的gc
    • **Full GC:**回收整个堆的内存
      • 触发条件:
        • System.gc()
        • 通过Minor GC进入老年代的平均大小 > 老年代的可用内存
        • 老年代空间不足;

3. 垃圾回收算法(内存回收方法论)

八股+面经_第13张图片

4. 垃圾收集器(内存回收具体实现)

  1. Serial:

    • 单线程,所有线程stw,

    • 新生代标记-复制,老年代标记-整理

    • 缺点:需要停止所有工作线程,效率低

    • 场景:对应用的实时性要求不高的client级别(桌面应用)的默认方式,单核服务器

      八股+面经_第14张图片
  2. ParNew:

    • Serial的多线程版本,stw, 复制算法

    • 新生代标记-复制,老年代标记-整理

    • 实际线程默认和cpu数量相同

    • 优点:有效利用cpu

    • 缺点:和Serial一样

    • 场景:Sever模式下的新生代,和CMS配合

  3. Parallel Scavenge:

  • 新生代收集器、复制算法,多线程

  • 与ParNew不同点:追求和精确控制高吞吐量,而ParNew尽可能缩短用户线程的停顿时间;

    • 高吞吐:线程运行时间/线程运行时间 + 垃圾回收时间
    • 例子:PS就是100秒回收一次垃圾,持续10秒,吞吐量为90%;PN就是50秒回收一次垃圾,持续7秒,吞吐量为86%。
  • 场景:注重高效利用CPU

  1. Serial Old

    • Serial的老年代版本,标记整理算法

    • 场景:client、单核。与PS收集器搭配

  2. Parallel Old

    • Parallel Scavenge的老年代版本,多线程,标记整理算法

    • JDK7,8默认老年代收集器

  3. CMS

    • Concurrent Mark Sweep

    • 多线程、标记清除算法

    • 特点:获取最短回收停顿时间

八股+面经_第15张图片
  • 流程:
    • 1、初始标记:GC Roots直接关联的对象,需要Stw
    • 2、并发标记:与用户线程并发,不需要Stw,执行Gc Roots Tracing
    • 3、重新标记:修正并发标记期间,发生变动的一些标记,需要Stw
    • 4、并发清除:标记清除
  • 优点:并发收集,低停顿
  • 缺点:
    • 对CPU资源敏感
    • 标记清除产生空间碎片
    • 并发清除过程中会产生新的垃圾,只能等下一次
  1. G1(Garbage-First)

    • 标记整理 + 复制

      • 特点:

        • 并行与并发
        • 分代收集:自己采用不同的收集方式去处理不同代的垃圾,不需要和其他收集器合作
        • 空间整合:无空间碎片
        • 可预测的停顿:可预测时间的停顿模型
      • 原理:

        • 将java堆分为大小相同的独立区域Region,新生代和老年代区域混合;

          八股+面经_第16张图片
          • 并发标记:知道哪些块基本是垃圾,就会从这些块下手(所以叫G1);
          • 停顿预测模型:
            • 根据之前垃圾回收的数据统计,估计出用户指定停顿时间内的回收块个数;
          • “尽力”满足指定的目标停顿时间,基于目标选择回收的区块数量;
  • 步骤;

    • 1、Minor GC

      • 复制算法、并行、stw
      • 动态调整年轻区大小:根据历史数据,和用户指定的停顿时间目标
      • 2、老年代收集
      • 初始标记:stw,伴随young gc,对Gc Roots直接关联对象进行标记
      • 扫描根引用区:即survivor区的对象直接到老年代对象的引用。(因为进行了YGC,新生代中只有survivor区存在对象)
      • 并发标记:寻找整个堆的存活对象,并发执行,可以被YGC中断
        • 如果整个region都是垃圾,直接被回收
        • 标记的同时计算region活性比例
      • 重新标记:stw,完成最后的标记,使用了STAB算法
        • 由于用户线程同时进行,需要修正之前的标记
        • 采用了比CMS更快的初始快照法:SATB算法
      • 清理:stw,复制算法。计算各个region的存活对象和垃圾比例,排序,识别可以混合回收的区域 。
      • 并发清理:识别并清理全是垃圾的老年代region
      • 3、混合式收集:
      • 除了整个年轻代收集, 还有上个阶段标记出的老年代的垃圾最多的区块;
      • 持续回收所有被标记的分区
      • 恢复到年轻代收集,进行新的周期
      • 必要时的Full Gc:
        • G1的初衷就是避免Full GC

总结

  • 7种收集器关系

    如果两个收集器之间存在连线,就说明它们可以搭配使用

img

  • 收集器总结
收集器 串/并行/并发 新/老 收集算法 目标 场景
Serial 串行 复制 响应速度优先 单CPU环境下的Client模式
Serial Old 串行 标记-整理 响应速度优先 单CPU环境下的Client模式、CMS的后备预案
ParNew 并行 复制 响应速度优先 多CPU环境时在Server模式下与CMS配合
Parallel Scavenge 并行 复制 吞吐量优先 在后台运算而不需要太多交互的任务
Parallel Old 并行 标记-整理 吞吐量优先 在后台运算而不需要太多交互的任务
CMS 并发 标记-清除 响应速度优先 集中在互联网站或B/S系统服务端上的Java应用
G1 并发 both 标记-整理+复制算法 响应速度优先 面向服务端应用,将来替换CMS

设计模式

单例模式

  1. 懒汉式 - 线程不安全

    public class Singleton{
    	private static Singleton instance;
    	private Singleton(){}
    	public static Singleton getInstance(){
    		if(instance == null){
    			instance = new Singleton();
    		}
    		return instance;
    	}
    }
    
  2. 懒汉式 - 线程不安全

    public class Singleton{
    	private static Singleton instance;
    	private Singleton(){}
    	public static synchronized Singleton getInstance(){
    		if(instance == null){
    			instance = new Singleton();
    		}
    		return instance;
    	}
    }
    
  3. 双重检验锁

    public class Singleton{
    	private static Singleton instance;
    	private Singleton(){}
    	public static Singleton getInstance(){
    		if(instance == null){		// single check
    			synchornized(Singleton.class){
    				if(instance == null){		//double check
    					instance = new Singleton();
    				}
    			}
    		}
    		return instance;
    	}
    }
    
  4. 饿汉式 - static final field

    public class Singleton{
     	//类加载时就初始化
    	private static final Singleton instance = new Singleton();
    	private Singleton(){}
    	public static Singleton getInstance(){
    		return instance;
    	}
    }
    
  5. 静态内部类 - static nested class

    public class Singleton{
    	private static class SingletonHolder(){
    		private static final Singleton instance = new Singleton();
    	}
    	private Singleton(){}
    	public static final Singleton getInstance(){
    		return SingletonHolder.instance;
    	}
    }
    
  6. 枚举 - Enum

    public class Singleton{
    	private Singleton(){}
    	/**
    	*枚举类型是线程安全的,并且只会装载一次
    	*/
    	public enum SingletonEnum{
    		INSTANCE;
    		private final Singleton instance;
    		SingletonEnum(){
    			instance = new Singleton();
    		}
    		private Singleton getInstance(){
    			return instance;
    		}
    	}
    	
    	public static Singleton getInstance(){
    		return SingletonEnum.INSTANCE.getInstance();
    	}
    }
    
    

MySQL

存储引擎

  • MySQL 支持哪些存储引擎

    • MySQL 5.5.5 前:默认MyISAM;后:默认InnoDB
    • 只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。
  • 存储引擎架构

    • 插件式架构,支持多种存储引擎(不同数据库表可以设置不同搜索引擎)
    • 存储引擎是基于表的,而不是数据库
  • MyISAM 和 InnoDB 区别(7点)

    • MyISAM 性能还行,特性不错,但不支持事务和行级锁,最大的缺陷就是崩溃后无法安全恢复。

    八股+面经_第17张图片

索引

常见的索引结构有: B 树, B+树 和 Hash、红黑树。在 MySQL 中,无论是 Innodb 还是 MyIsam,都使用了 B+树作为索引结构。

1. 优缺点

优点

  • 使用索引可以大大加快 数据的检索速度(大大减少检索的数据量), 这也是创建索引的最主要的原因。
  • 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性

缺点

  • 创建索引和维护索引需要耗费许多时间。当对表中的数据进行增删改的时候,如果数据有索引,那么索引也需要动态的修改,会降低 SQL 执行效率。
  • 索引需要使用物理文件存储,也会耗费一定空间

2. 底层数据结构

B&B+树

  • 为啥不用哈希表做MySQL索引数据结构?

    • Hash 索引不支持顺序和范围查询,并且,每次 IO 只能取一个。
    • 试想,SELECT * FROM tb1 WHERE id < 500;,树直接遍历比 500 小的叶子节点就够了;哈希还要把1-499数据hash计算一遍来定位
  • B树和B+树区别?(3点)

    八股+面经_第18张图片
  • B+树比B树的优势

1.单一节点存储更多的元素,使得查询的IO次数更少;
  2.所有查询都要查找到叶子节点,查询性能稳定;
  3.所有叶子节点形成有序链表,便于范围查询。

3. 索引类型总结

八股+面经_第19张图片

事务

1. ACID

原子性Atomicity) : 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;

一致性Consistency): 执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;

隔离性Isolation): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;

持久性Durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

只有保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障。也就是说 A、I、D 是手段,C 是目的!

八股+面经_第20张图片

2. 并发事务问题

  • 脏读(Dirty read)

    某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的

  • 丢失修改(Lost to modify)

    在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。

  • 不可重复读(Unrepeatable read)

    在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。

  • 幻读(Phantom read)

    在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

3. 并发事务控制方式

悲观控制模式

  • 共享锁(S 锁) :又称读锁,事务在读取记录的时候获取共享锁,允许多个事务同时获取(锁兼容)。
  • 排他锁(X 锁) :又称写锁/独占锁,事务在修改记录的时候获取排他锁,不允许多个事务同时获取。如果一个记录已经被加了排他锁,那其他事务不能再对这条记录加任何类型的锁(锁不兼容)。

MVCC

乐观控制模式

多版本并发控制(MVCC,Multiversion concurrency control) 在 MySQL 中实现所依赖的手段主要是: 隐藏字段、read view、undo log

  • undo log : undo log 用于记录某行数据的多个版本的数据。
  • read view 和 隐藏字段 : 用来判断当前版本数据的可见性。

4. 隔离级别

  1. 读取未提交(READ-UNCOMMITTED) : 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。

  2. 读取已提交(READ-COMMITTED) : 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。

  3. 可重复读(REPEATABLE-READ) : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

  4. 可串行化(SERIALIZABLE) : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

八股+面经_第21张图片

锁机制

MVCC

RC和RR下 MVCC 的差异

在事务隔离级别 RCRR (InnoDB 存储引擎的默认事务隔离级别)下,InnoDB 存储引擎使用 MVCC(非锁定一致性读),但它们生成 Read View 的时机却不同

  • 在 RC 隔离级别下的 每次select 查询前都生成一个Read View (m_ids 列表)

  • 在 RR 隔离级别下只在事务开始后 第一次select 数据前生成一个Read View(m_ids 列表)

Redis

为什么用redis做mysql缓存?

1、高性能

  • MySQL从硬盘读取,慢。将用户缓存数据存在redis中,下次直接从缓存获取,相当于直接操作内存。
  • 为啥这么快?
    • 基于内存,访问速度是磁盘的上千倍
    • 基于reactor模式设计开发了一套高效事件处理模型,主要是单线程事件循环和io多路复用
    • 内置多种优化后的数据结构实现

2、 高并发

  • 单台设备的Redis的QPS(Query Per Second,每秒钟处理完请求的次数) 是 MySQL 的10倍
  • 直接访问 Redis 能够承受的请求远远大于直接访问 MySQL

数据结构

5 种基础数据结构 :String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。

3 种特殊数据结构 :HyperLogLogs(基数统计)、Bitmap (位存储)、Geospatial (地理位置)。

  • 常见数据结构

八股+面经_第22张图片
  • 底层数据结构

八股+面经_第23张图片

线程模型

  • 1. 单线程模式

八股+面经_第24张图片

  • 2. 单线程 v.s 多线程

八股+面经_第25张图片

缓存读写策略

1. 旁路缓存模式

  • 适用:读请求比较多的场景
  • 服务端同时维系 db 和 cache,以 db 的结果为准
  • 缓存读写步骤:
    • 写:
      • 先更新 db
      • 然后直接删除 cache
    • 读:
      • 从 cache 中读取数据,读取到就直接返回
      • cache 中读取不到的话,就从 db 中读取数据返回
      • 再把数据放到 cache 中

2. 读写穿透

  • 适用:读请求比较多的场景

3. 异步缓存写入

  • 适用:读请求比较多的场景

计算机网络

HTTP与HTTPS

  • 区别
    • 传输安全:HTTP 是明文传输,存在安全风险的问题;HTTPS加密传输
    • 连接方式:HTTP是TCP;HTTPS是TCP基础上进行SSL/TLS
    • 端口号不同:HTTP 是 80;HTTPS是 443
    • 数字证书:HTTPS需要向CA申请数字证书
  • HTTPS解决了HTTP哪些问题?
    • 信息加密:交互信息无法被窃取,但你的号会因为「自身忘记」账号而没。
    • 校验机制:无法篡改通信内容,篡改了就不能正常显示,但百度「竞价排名」依然可以搜索垃圾广告。
    • 身份证书:证明淘宝是真的淘宝网,但你的钱还是会因为「剁手」而没。

三次握手(建立TCP连接)

八股+面经_第26张图片

一次握手:客户端发送带有 SYN(SEQ=x) 标志的数据包 -> 服务端,然后客户端进入 SYN_SEND 状态,等待服务器的确认;

二次握手:服务端发送带有 SYN+ACK(SEQ=y,ACK=x+1) 标志的数据包 –> 客户端,然后服务端进入 SYN_RECV 状态

三次握手:客户端发送带有 ACK(ACK=y+1) 标志的数据包 –> 服务端,然后客户端和服务器端都进入ESTABLISHED 状态,完成TCP三次握手。

四次挥手(断开TCP连接)

八股+面经_第27张图片

第一次挥手 :客户端发送一个 FIN(SEQ=X) 标志的数据包->服务端,用来关闭客户端到服务器的数据传送。然后,客户端进入 FIN-WAIT-1 状态。

第二次挥手 :服务器收到这个 FIN(SEQ=X) 标志的数据包,它发送一个 ACK (SEQ=X+1)标志的数据包->客户端 。然后,此时服务端进入CLOSE-WAIT状态,客户端进入FIN-WAIT-2状态。

第三次挥手 :服务端关闭与客户端的连接并发送一个 FIN (SEQ=y)标志的数据包->客户端请求关闭连接,然后,服务端进入LAST-ACK状态。

第四次挥手 :客户端发送 ACK (SEQ=y+1)标志的数据包->服务端并且进入TIME-WAIT状态,服务端在收到 ACK (SEQ=y+1)标志的数据包后进入 CLOSE 状态。此时,如果客户端等待 2MSL 后依然没有收到回复,就证明服务端已正常关闭,随后,客户端也可以关闭连接了。

TCP v.s UDP

  • 七点不同:

八股+面经_第28张图片

  • UDP 一般用于即时通信,比如: 语音、 视频 、直播等等。

  • TCP 用于对传输准确性要求特别高的场景,比如文件传输、发送和接收邮件、远程登录等等。

操作系统

Spring

IoC

IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。

为什么叫控制反转?

  • 控制 :指的是对象创建(实例化、管理)的权力
  • 反转 :控制权交给外部环境(Spring 框架、IoC 容器)

八股+面经_第29张图片

AoP

AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

面试题目

拼多多 3.23

项目:不动产估值系统

  • 学到了什么?提到scrapy理论,问原理
八股+面经_第30张图片
  • 多源异构数据集?数据类型是什么?
  • 机器学习算法怎么实现的?用了哪些特征?
  • 评估指标是啥(准确率)?r2的含义是什么?
    • R2_score直观且不受量纲影响。其数值大小反映了回归贡献的相对程度,即在因变量Y的总变异中,回归关系所能解释的百分比,其值越高,说明模型的解释性越好。
  • 还用过其他评估指标吗?还知道其他评估指标吗?
    • 平均绝对误差、均方误差、均方根差、均方根百分误差、决定系数R2
    • 前四种问题:量纲不同时,难以衡量模型效果好坏,并且可读性较差
八股+面经_第31张图片
  • 训练集和测试集怎么划分的?为什么这么划分?(这么划分结果最好
  • 为什么其他划分方式结果不好?有分析吗?
  • 训练集测试集划分比例有什么影响?过拟合是什么意思?
  • 个人能力比较突出的是什么?
  • 华融实习都是自己做的吗?
  • 遇到过什么问题?怎么解决?印象比较深花时间比较多的(提到了版本不一致报错)
  • java遇到版本不一样问题怎么办?a库和b库都用到了c库

java

  1. 类加载机制

  2. 垃圾回收机制

数据库

  1. redis和mysql有什么不同?为啥用redis做缓存?

  2. redis数据结构?

算法

上海[180.65.28.0, 186.75.28.0]

重庆[101.0.0.0,101,255,255,255]

…一共十万行

然后给ip地址(字符串),返回城市名称,没有对应城市返回""

反问:什么部门?做什么?跨境电商 海外业务 推荐搜索

美团-履约 3.24

项目

  1. 爬虫策略 数据量

  2. 用过大数据挖掘吗?spark这些?

MySQL

  1. 介绍索引

  2. B树和B+树区别

  3. 还有别的索引吗?都用的B+树吗?

  4. 聚簇索引 非聚簇索引

  5. 主键索引 非主键索引

java

  1. 垃圾回收算法

  2. java的锁synchronize,lock

  3. 介绍线程池

  4. 强引用 弱引用

算法:2. 两数相加 - 力扣

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummyHead=new ListNode(-1);
        ListNode p=dummyHead;
        int add=0;
        while(l1!=null||l2!=null||add>0){
            int a=l1==null?0:l1.val;
            int b=l2==null?0:l2.val;
            int ans=a+b+add;
            p.next=new ListNode(ans%10);
            add=ans/10;
            p=p.next;
            if(l1!=null)
                l1=l1.next;
            if(l2!=null)
                l2=l2.next;
        }
        return dummyHead.next;
    }
}

联想 3.27

图书项目

  1. spring boot和spring的区别?
    • 最大的区别在于Spring Boot的自动装配原理
    • 比如:
      • 创建Web程序时:Spring-导入几个Maven依赖,Spring Boot-只需要一个Maven依赖
      • 开启功能:Spring-XML文件配置,Spring Boot-不用XML配置,只需要写一个配置类
    • Spring Boot是一个微服务框架,延续了Spring框架的核心思想IOC和AOP,简化了应用的开发和部署,是Spring的完善和扩展
  2. mysql中有几种表?分别存的数据项是什么?
    • user,book,category(图书类别),admin_role(用户角色),admin_permission(用户权限),admin_role_menu(用户角色菜单),admin_role_permission(用户角色权限)
    • book表:id,cover,title,author,date,press,abs,cid(类别做外键)
  3. 项目中redis用什么客户端部署?
    • Java 访问 Redis 主要是通过 JedisLettuce 两种由不同团队开发的客户端(提供访问、操作所需的 API),Jedis 比较原生,Lettuce 提供的能力更加全面
    • 本项目用Spring Data Redis,Spring Data Redis是在 Lettuce 的基础上做了一些封装,与 Spring 生态更加贴合,使用起来也更简便。
  4. redis用的哪种数据结构存储图书?
    • RedisTemplate是 Spring Data Redis 提供的一个完成 Redis 操作、异常转换和序列化的类
    • String类型key,Set keys,List< Book >存图书列表
  5. List存取的api了解吗?
    • append,get
  6. redis缓存是所有图书都存进去吗?
  7. 数据库组建怎么实现的?
  8. mysql中事务是怎么添加的?
    • 步骤1:开启事务
      set autocommit=0;
      start transaction;可选的
    • 步骤2:编写事务中的sql语句(select、insert、update、delete)
      语句1;
      语句2;
    • 步骤3:结束事务
      commit;提交事务
      rollback;回滚事务
  9. 一个mapper两个update怎么保证事务不冲突?(答锁,纠正我锁是保证数据一致性的
    • MVCC
      • undo log
      • 隐藏字段
      • ReadView

抵押品项目

怎么构建的数据集?

java

  1. static和final什么时候用?为什么要用?

    • static
      • 加载:类加载时初始化(加载)完成
      • 可修饰:内部类、方法、成员变量、代码块
      • 不可修饰:外部类、局部变量
      • 作用:方便调用没有创建对象的方法/变量
    • final
      • 加载:final可以在编译(类加载)时初始化,也可以在运行时初始化,初始化后不能被改变
      • 可修饰:成员变量、方法、类以及本地变量
      • 一旦你将引用声明作 final,你将不能改变这个引用了,保证数据安全性
    • static final
      • 可修饰:成员变量、方法、内部类
      • 被static final修饰意义如下
        • 成员变量:属于类的变量且只能赋值一次。
        • 方法:属于类的方法且不可以被重写。
        • 内部类:属于外部类,且不能被继承。
  2. Object常用hashCode()和equals(),什么时候需要重写?

    • 1)当我们需要重新定义两个对象是否相等的条件时,需要进行重写。比如通常情况下,我们认为两个不同对象的某些属性值相同时就认为这两个对象是相同的。

      例如:我们在HashMap中添加元素时,我们认为当key相同时,两个元素就相同,但是默认的Object中的equals(),只是单纯的比较两个元素 的内存地址是否相同,不能满足我们的要求,所以需要重写。

    • 2)当我们自定义一个类时,想要把它的实例保存在集合时,就需要重写equals()和hashCode()方法

  3. ArrayList的底层数据结构

    • Object[]数组
  4. HashMap的底层数据结构?

    • jdk1.8之前:数组+链表(链表散列)
    • jdk1.8之后:链表长度>阈值(默认8),将其转化为红黑树,减少搜索时间
  5. HashMap数组中怎么存的?

    • 存的hash值,链表中存键值对
    八股+面经_第32张图片
  6. 哈希冲突是什么?

  7. synchronize怎么用?啥时候用?

    • 修饰实例方法:进入同步代码前要获得 当前对象实例的锁
    • 修饰静态方法:进入同步代码前要获得 当前 class 的锁
    • 修饰代码块
      • synchronized(object) 表示进入同步代码库前要获得 给定对象的锁
      • synchronized(类.class) 表示进入同步代码前要获得 给定 Class 的锁

算法(口述)

  • 两个数组找交集,令时间复杂度最小(答用set 时间复杂度是多少?
    • 排序 + 双指针:初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,且该数字不等于 pre ,将该数字添加到答案并更新 pre 变量,同时将两个指针都右移一位。当至少有一个指针超出数组范围时,遍历结束。

蚂蚁-数金 3.28

押品项目

  1. 从哪些维度对数据进行挖掘?得到什么样的结果?哪些对算法模型有决定性作用
  2. 系统开发后端是不是增删改查这些?用的什么数据库

java

  1. 保证线程安全的办法?(答锁,问我还有其他吗,没答出来

    • 互斥同步:synchronized是最常用的
    • 非阻塞同步
    • 无同步方案
  2. 说说对锁的了解(答乐观锁和悲观锁

    • 乐观锁实现:版本号orCAS

    • 悲观锁实现:synchronizedLock等独占锁就是悲观锁

  3. 悲观锁用什么实现?(答synchronized和ReentrantLock

  4. synchronized和其他独占锁底层是怎么实现的?

    • synchronized底层:
  5. java为什么会存在线程安全的问题?底层原因是什么?(答并发,跟我说是表象,问更深层是什么原因

  6. java本身jvm或者内存什么样的设计特点决定它存在这样的问题?(答线程共享堆和方法区资源,同时修改会发生安全问题,他还问更深层的是什么

    • 线程共享:方法区,堆(有线程安全问题)

    • 线程独享:栈、本地方法栈、计数器(不存在线程安全问题)

  7. 了解java内存模型吗?新增一个线程,线程里的变量存在于什么地方?(答栈

  8. 这个栈空间是共享的还是独享的?(答共享的,纠正我有一部分共享一部分独享,共享function,独享变量

    变量独享,做复制,拷贝到工作内存,更改完需要回刷,产生XXx操作,是问题的根本原因

  9. ConcurrentHashMap的源码了解(答了一下初始化源码

mysql

  1. 索引结构(答b+树
  2. b+树特点
  3. b+树每一层都是链表(我说只有叶子是,纠正我mysql不是标准b+树,是变种
  4. 查询语句建索引,abc三个字段,有一条语句“a=?,c=?”,“?”是占位符,这个语句能不能用到abc复合索引?(答能,问原因不会

redis

  1. 读数写数单线程,那为什么性能那么好?(三点

Spring boot

  1. 动态加载和动态配置化为开发带来了哪些便利?

  2. 你在开发中用到了什么动态加载和动态配置化?

    (答spring用xml,sb用配置类,纠正:Spring也可以用注解不用xml配置,动态加载和用不用配置没啥关系

算法

  1. 线程安全的单例模式
  2. 快排
  3. 有序数组找第一个大于x的元素下标

其他

​ 工作和学习中做的最有挑战或者最有成就感的一件事是什么?

美团-酒旅 3.30

押品项目

  1. 难点?
  2. 对数据挖掘的结果是什么?什么数据对结果影响比较大?
  3. 再来一个数据集?怎么把它变成同构的?
  4. 算法还有提升空间吗?有多少提升空间?怎么提升?试过什么方法?提升了多少?
  5. 没用过的那些算法准确率有多少?
  6. 系统都有什么功能?
  7. 实习做的算法?为啥找开发?

图书项目

  1. 怎么用的maven?
  2. 为什么采用shiro框架?还知道什么安全框架?(答Spring Security
  3. Spring Security和shiro有什么区别?为什么没用Spring Security?
  4. 项目里redis用的哪种数据结构?键是什么?(答List,键是图书id,他质疑我键不对

Java

  1. java异常机制的了解

    在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。

image-20230403224929321
  1. 设计一个java线程池

  2. Integer a=128; Integer b=128; System.out.println(a==b);
    

    结果是啥?(应该是true,我答的false,他问我不是有常量池吗

  3. public static void main(String[] args) {
        Integer numValue=new Integer(1);
        int a=1;
        int b=2;
        Integer nullValue=null;
        if(a==1)
            b=nullValue;
        else if(b==2)
            a=nullValue;
        System.out.println(numValue);
        System.out.println(nullValue);
        System.out.println(a);
        System.out.println(b);
    }
    

    结果是啥?(代码大概是这样,结果是编译错误T_T,int型(b)不能为null,Integer可以为null

  4. 类加载机制?

  5. 知道哪些类加载器(ClassLoader)?

    • BootstrapClassLoader(启动类加载器) :最顶层的加载类,主要用来加载 JDK 内部的核心类库

    • ExtensionClassLoader(扩展类加载器) :主要负责加载 %JRE_HOME%/lib/ext 目录下的 jar 包和类以及被 java.ext.dirs 系统变量所指定的路径下的所有类。

    • AppClassLoader(应用程序类加载器) :面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。

  6. 垃圾回收机制的了解?(答回收算法,纠正我分代收集不算一种算法

  7. 哪几种收集器用的标记-整理?哪几种用的复制?

操作系统

  1. 构造一个死锁

    public class DeadLock {
    
    
        private class Running1 implements Runnable {
            /*
             * This method request two locks, first String and then Integer
             */
            @Override
            public void run() {
                while (true) {
                    synchronized (String.class) {
                        System.out.println("Thread1 Aquired lock on String.class object");
        
                        synchronized (Integer.class) {
                            System.out.println("Thread1 Aquired lock on Integer.class object");
                        }
                    }               
                }
            }
        
        }
        
        private class Running2 implements Runnable {
            /*
             * This method also requests same two lock but in exactly
             * Opposite order i.e. first Integer and then String
             * This creates potential deadlock, if one thread holds String lock
             * and other holds Integer lock and they wait for each other, forever
             */
            @Override
            public void run() {
                while (true) {
                    synchronized (Integer.class) {
                        System.out.println("Thread2 Aquired lock on Integer.class object");
        
                        synchronized (String.class) {
                            System.out.println("Thread2 Aquired lock on String.class object");
                        }
                    }               
                }
            }       
        }
        
        public static void main(String[] args) {
            DeadLock deadLock = new DeadLock();
            Running1 r1 = deadLock.new Running1();
            Running2 r2 = deadLock.new Running2();
        
            Thread thread1 = new Thread(r1);
            Thread thread2 = new Thread(r2);
        
            thread1.start();
            thread2.start();
        }
    
    }
    

    在上面这个例子中,我们有两个线程,以相反的顺序去获取两个锁,最后陷入了Thread1持有String锁,等待Integer锁,Thread2持有Integer锁,等待String锁的无限等待,即死锁情景

MySQL

  1. InnoDB和MyISAM的区别(7点

  2. 为什么InnoDB的性能更强大?

    • MyISAM 因为读写不能并发,它的处理能力跟核数没关系。
    • 在读写混合模式或者只读模式下,随着 CPU 核数的增加,InnoDB 的读写能力呈线性增长。
  3. 为什么要主键自增?

    • 1.数据记录本身被存于主索引的叶子节点上
    • 2.mysql会根据其主键将其插入适当的节点和位置
    • 3.表使用自增主键,在每次插入新的记录时,记录会顺序添加到当前索引节点的后续位置

redis

  1. 说说对redis的了解(答高性能和高并发

  2. redis为什么用单线程?

    • 单线程编程容易并且更容易维护;
    • Redis 的性能瓶颈不在 CPU ,主要在内存和网络;
    • 多线程就会存在死锁、线程上下文切换等问题,甚至会影响性能。
  3. 哪几种底层数据结构?每种数据结构的使用场景?

    • String

      • 存储常规数据

      • 计数

      • 分布式锁

    • List

      • 信息流展示

      • 消息队列

    • Set

      • 存放的数据不能重复(点赞…

      • 获取多个数据源交集、并集和差集(共同好友、音乐推荐…

      • 随机获取数据源中的元素(抽奖系统…

    • Hash

      • 对象数据存储(用户信息、文章信息…
    • Zset

      • 随机获取数据源中的元素根据某个权重进行排序(朋友圈的微信步数排行榜…

      • 存储的数据有优先级或者重要程度(优先级任务队列

  4. io多路复用是怎么复用的?

    • 目的:让单线程(进程)的服务端应用同时处理多个客户端的事件

    • 含义:**“多路”指的是多个网络连接客户端,“复用”**指的是复用同一个线程(单进程)。

      I/O 多路复用其实是使用一个线程来检查多个Socket的就绪状态,在单个线程中通过记录跟踪每一个socket(I/O流)的状态来管理处理多个I/O流。

    八股+面经_第33张图片

算法

  1. sql:student表里找成绩第二的

  2. 有序数组,遍历一次找出所有a+b=m的数字(要运行)

    追问:数组是空怎么办?数组是[2,2,5,5]怎么办?

反问:对校招生的建议(告诉我美团注重基础

       thread1.start();
       thread2.start();
   }

}


在上面这个例子中,我们有两个线程,以相反的顺序去获取两个锁,最后陷入了Thread1持有String锁,等待Integer锁,Thread2持有Integer锁,等待String锁的无限等待,即死锁情景

**MySQL**

1. InnoDB和MyISAM的区别(7点
2. **为什么InnoDB的性能更强大?**
- MyISAM 因为读写不能并发,它的处理能力跟核数没关系。
- 在读写混合模式或者只读模式下,随着 CPU 核数的增加,InnoDB 的读写能力呈线性增长。

3. **为什么要主键自增?**
- 1.数据记录本身被存于主索引的叶子节点上
- 2.mysql会根据其主键将其插入适当的节点和位置
- 3.表使用自增主键,在每次插入新的记录时,记录会顺序添加到当前索引节点的后续位置

**redis**

1. 说说对redis的了解(答高性能和高并发

2. **redis为什么用单线程?**

- 单线程编程容易并且更容易维护;
- Redis 的性能瓶颈不在 CPU ,主要在内存和网络;
- 多线程就会存在死锁、线程上下文切换等问题,甚至会影响性能。

3. 哪几种底层数据结构?每种**数据结构的使用场景?**

- **String**
  - 存储常规数据

  - 计数

  - 分布式锁

- **List**
  - 信息流展示

  - 消息队列

- **Set**
  - 存放的数据不能重复(点赞...

  - 获取多个数据源交集、并集和差集(共同好友、音乐推荐...

  - 随机获取数据源中的元素(抽奖系统...

- **Hash**
  - 对象数据存储(用户信息、文章信息...

- **Zset**
  - 随机获取数据源中的元素根据某个权重进行排序(朋友圈的微信步数排行榜...

  - 存储的数据有优先级或者重要程度(优先级任务队列

4. **io多路复用是怎么复用的?**

- 目的:让单线程(进程)的服务端应用同时处理多个客户端的事件

- 含义:**“多路”**指的是多个网络连接客户端,**“复用”**指的是复用同一个线程(单进程)。

  I/O 多路复用其实是使用一个线程来检查多个Socket的就绪状态,在单个线程中通过记录跟踪每一个socket(I/O流)的状态来管理处理多个I/O流。

![在这里插入图片描述](https://img-blog.csdnimg.cn/c831c3aee0434cda8b9c6a0449e3b97b.png)

**算法**

1. sql:student表里找成绩第二的

2. 有序数组,遍历一次找出所有a+b=m的数字(要运行)

追问:数组是空怎么办?数组是[2,2,5,5]怎么办?

**反问**:对校招生的建议(告诉我美团注重基础

你可能感兴趣的:(java)