链接

JavaGuide:https://snailclimb.gitee.io/javaguide-interview
疯狂创客圈:https://www.cnblogs.com/crazymakercircle/p/9904544.html

面试感悟——一名3年工作经验的程序员应该具备的技能

五月的仓颉:优质博客、多线程面试题、面试感悟↑

MySQL

事务的四大特性

  1. 原子性
  2. 一致性
  3. 隔离性
  4. 持久性

    并发事务带来的问题

  5. 脏读:读取到其他事务未提交的数据

  6. 丢失修改:事务修改结果被另一个事务修改
  7. 不可重复读:一次事务读取两次数据不同
  8. 幻读:一次事务两次读取的记录数不同

    事务的隔离级别

  9. 读取未提交(脏读、不可重复读、幻读)

  10. 读取已提交(丢失修改、不可重复读、幻读)
  11. 可重复读:MySQL 默认级别(幻读)
  12. 可串行化:最高级别,各事务依次执行,不互相产生干扰

    索引类型

  13. 主键索引(聚簇索引)

  14. 唯一索引
  15. 普通索引
  16. 组合索引
  17. 全文索引

    多线程

    多线程发生死锁的条件

  18. 互斥使用

  19. 不可抢占
  20. 请求与保持
  21. 循环等待

    线程状态

  22. 新建

  23. 就绪、可运行
  24. 阻塞
  25. 等待
  26. 计时等待
  27. 终止

    JVM 内存区域

    Java程序设计语言、Java虚拟机、Java类库这三部分统称为JDK(JavaDevelopment Kit)

    1. 程序计数器

    程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。

字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

总结:

  • 程序计数器是线程私有的;
  • 程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器;
  • 字节码解释器通过改变程序计数器一次读取指令,从而进行流程控制(分支、循环、异常处理、顺序执行);
  • 多线程环境下,程序计数器记录当前线程的执行位置,在线程切换完成后保证程序的正确执行;

    2. 栈

Java虚拟机栈(Java Virtual Machine Stack)也是线程私有的,它的生命周期与线程相同。

虚拟机栈描述的是 Java 方法执行的线程内存模型:每个方法被执行的时候,Java 虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

局部变量表存放了编译期可知的各种 Java 虚拟机基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,它并不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或者其他与此对象相关的位置)和 returnAddress 类型(指向了一条字节码指令的地址)。

局部变量表中的这些数据类型在局部变量表中的存储空间以局部变量槽(Slot)来表示,其中 64 位长度的 long 和double 类型的数据会占用两个变量槽,其余的数据类型只占用一个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。请读者注意,这里说的“大小”是指变量槽的数量,虚拟机真正使用多大的内存空间(譬如按照 1 个变量槽占用 32 个比特、64 个比特,或者更多)来实现一个变量槽,这是完全由具体的虚拟机实现自行决定的事情。

总结:

  • Java 虚拟机栈是线程私有的;
  • Java 虚拟机栈是由一个个栈帧组成的,每个栈帧都包含局部变量表操作数栈动态连接方法出口等信息;
  • 局部变量表中存储了 Java 的基本数据类型对象引用reference 类型)以及 returnAddress 类型,以局部变量槽表示其存储空间;
  • Java 中每一次方法调用都会有一个对应的栈帧被压入栈,每一个方法调用结束(return 或 异常)都会有一个对应的栈帧被弹出。

    3. 堆

    Java 堆(Java Heap)是虚拟机所管理的内存中最大的一块。

此内存区域的唯一目的就是存放对象实例,Java世界里“几乎”所有的对象实例都在这里分配内存。所有的对象实例以及数组都应当在堆上分配。

从回收内存的角度看,由于现代垃圾收集器大部分都是基于分代收集理论设计的,所以 Java 堆中经常会出现“新生代”,“老年代”,“永久代”,“Eden空间”,“From Survivor空间”,“To Survivor空间” 等。

总结:

  • 堆是线程共享的;
  • 堆是垃圾回收的主要区域,所有又称为 GC 堆;
  • 堆的唯一目的是存放对象实例,几乎所有的对象实例数组都在堆内存分配空间;
  • JDK1.7 字符串常量池被从方法区拿到了堆中;
  • 根据分代垃圾收集算法,堆可以被细分为新生代和老年代,新生代可以分为 Eden 空间、From Survivor、To Survivor 空间(幸存区,s0,s1);

4. 方法区

方法区(Method Area)用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

  • 方法区是线程共享的;
  • 方法区主要存储已被虚拟机加载的类型信息、常量(运行时常量池)、静态变量、即时编译器编译后的代码缓存等数据;
  • 方法区是是一种概念,不同虚拟机对该空间的实现不同。永久代就是 HotSpot 虚拟机对虚拟机规范中方法区的一种实现方式;
  • 1.7 时字符串常量池和静态变量已经被移除方法区;1.8 时方法区(HotSpot的永久代)被元空间(MetaSpace)取代,元空间使用的时直接内存(非 Java 虚拟机内存区域);