渣渣大学生三年的学习笔记:Java 基础知识整理

前言

下面特别的 emoji 标识

⛔:可以直接忽略
:特别重要
⭐、:重要
:待完善
:重要的子知识点
、、、:有趣的知识点
:踩坑

注:下面每个知识点都是可以点进去查看全文的,这里只是为了方便快速预览,所以把重要的知识点总结了出来~

Java 基础

Java 常用的方法与语法

Java 包装类相关的问题
主要知识点:

  • 拆装箱
  • String 直接赋值与 new String 的区别(建议去看下 JVM 那里的 String 常量部分)
  • 包装类的比较
  • Integer 的缓存 “坑”(其实就是包装类的常量池)

Java 反射学习
主要就是介绍了一下反射的常用方法,如何在运行时取得对象的信息(为代理模式打好了基础)

  • 搭配学习:Java 代理模式

Java 时间处理相关学习
主要知识点:

  • SimpleDateFormat 线程不安全
  • Java8 后提供的新时间工具

Java 枚举的使用 ⭐
主要知识点:

  • 枚举的底层原理(单例模式)
  • 枚举的构造方法
  • 枚举实现单例
  • 枚举实现策略模式

Java 泛型
主要知识点:

  • 类型擦除
  • 通配符(上下界)

JVM 部分

Java JVM学习-JVM基本概念 ⭐
主要知识点:

  • Java 源文件到运行再到最后的卸载的整个执行流程
    • JVM 中一个 class 文件的一生
    • JVM 的执行引擎
  • JRE、JDK 和 JVM 的关系
    • JVM 的生命周期
    • JVM 的架构模型(栈的指令集架构)

Java JVM学习-类加载器 ⭐
主要就是理解 双亲委派机制 的工作原理,为下面类加载机制奠定了基础

  • 类加载器的分类
    • 启动类加载器(BootstrapClassLoader,这个类加载使用 C/C++ 语言实现的)
    • 扩展类加载器(ExtClassLoader) ⛔
    • 应用程序类加载器(AppClassLoader,该类加载是程序中默认的类加载器,一般来说,Java 应用的类都是由它来完成加载)
    • 用户自定义类加载器 ⛔
  • 双亲委派机制(自顶而下)

Java JVM学习-类加载机制
主要知识点:

  • 类的生命周期(这几个过程需要理解对应的阶段干了什么)
  • 类的初始化阶段(区分 执行时机不同,主要就是理解静态方法\变量和普通方法\变量的区别)
  • 类加载子系统(这个就是联系上面的那个 类加载器)

Java JVM学习-创建一个对象
讲述了一个 Java 对象是如何被创建出来的,以及 Java 对象头的内容,最后还补充了如何访问一个 Java 对象

  • 创建对象的步骤(这个图最好背下来) ⭐
  • 加载类元信息(类加载检查)
  • 为对象分配内存(指针碰撞法和空闲列表的应用场景)
  • 处理对象创建时的并发安全问题(CAS 和 TLAB 的工作方式)
  • 对象执行初始化的过程(设置属性的零值,填充对象头信息,最后才是执行构造方法)
  • 对象的内存布局(主要看对象头包含的信息)
  • 如何进行对象的访问定位?(直接指针或者使用句柄的方式)

Java JVM学习-虚拟机栈
Java 虚拟机栈是线程私有的,它的生命周期和线程相同,描述的是 Java 方法执行的内存模型,每次方法调用的数据都是通过栈传递的。

  • 运行时数据区的结构(程序计数器(PC寄存器)、栈、本地栈是线程私有的,且PC寄存器和虚拟机栈是分开的)
  • PC 寄存器,即程序计数寄存器(用来存储指向下一条指令的地址)
  • 栈中可能出现的异常(StackoverflowError)
  • 栈中存储什么?(存储的单位是栈帧,但是一般一个方法对应一个栈帧)
  • 局部变量表(主要用于存方法里面的形参、局部变量、方法返回值等)
  • 栈顶缓存技术(将栈顶元素全部缓存在物理 CPU 的寄存器中,以此降低对内存的读/写次数)
  • 动态链接(指向运行时常量池 的方法引用,多态实际上也是用这个动态链接实现的) ⭐
  • 静态链接和动态链接(在 JVM中,将符号引用转换为调用方法的直接引用与方法的绑定机制相关,其实就是重载的原理)
  • 方法的调用:虚方法表(查找虚方法实际位置的一个优化,延续上一节的展开)
  • 局部变量的逃逸分析(其实就是返回了一个引用出去,而不是内部产生在内部消亡)

Java JVM学习-堆的结构
一个 JVM 实例只存在一个堆内存,堆也是 Java内存管理的核心区域。“几乎” 所有的对象实例都在这里分配内存(JIT 编译器可能会把它丢到栈里面分配)

  • 堆的结构:新生区 + 养老区 + 元空间\永久区(主要分清 Java7之前 和 Java8 的区别)
  • 永久代和方法区的关系?元空间和方法区的关系?(永久代和元空间都只是方法区的一个具体实现而已)⭐
  • 为什么要使用元空间代替永久代?(避免方法区导致的 OOM 错误,所以将其丢到本地内存)⭐
  • 年轻代与老年代的区别?(前者存放生命周期较短的瞬时对象,后者存生命周期长的对象)⭐
  • 对象分配内存(就是对象如何在年轻代的 Eden 空间、Survivor0 空间和 Survivor1 空间中横跳,有些大的对象在 Eden 区无法存储时候,将直接进入老年代)
  • 堆空间的参数设置 ⭐
  • 堆是分配对象存储的唯一选择吗?(逃逸分析)

Java JVM学习-本地方法 ⛔
在学习方法区前先快速过一下本地方法区

  • 什么是本地方法?(该方法的实现由非 Java 语言实现,比如 C)
  • 为什么使用 Native Method?
  • 本地方法栈

‍ Java JVM学习-方法区
方法区用于存储已被虚拟机加载的类型信息(构造方法 / 接口定义)、常量、静态变量、即时编译器编译后的代码缓存等。

  • 栈、堆、方法区的交互关系
  • 永久代和方法区的关系?元空间和方法区的关系?(永久代和元空间都只是方法区的一个具体实现而已)⭐
  • 方法区的内部结构(用于存储已被虚拟机加载的类型信息(构造方法 / 接口定义)、常量、静态变量、即时编译器编译后的代码缓存 等)
  • Class 文件中的 “常量池”(其实就是常量池表,指向字面量和对类型、域和方法的符号引用)
  • 运行时常量池(这个才是真正意义上的常量池,它位于方法区中,常量池表就是指向它) ⭐
  • 方法区垃圾回收(主要回收两部分内容:常量池中废弃的常量和不再使用的类型)

Java JVM学习-String 字符串 ⭐
1.7 版本之后,字符串常量池已经转移到堆区,之前是永久代中,这里补充了一些常见面试题中 String 创建对象坑的理解

  • String 的基本特性(jdk8及以前内部定义了 char[] 用于存储字符串数据。jdk9 时改为 byte[],且 String 声明为 final
  • String 底层的 HashTable(String 的 String Pool是一个 固定大小的 Hashtable)
  • String 的内存分配(字符串常量池的位置在 Java堆内。(因为方法区默认比较小,垃圾回收频率低))
  • 字符串拼接操作的原理(变量拼接的原理是 StringBuilder,虽然它是非线程安全,但是因为用完就销毁,所以无关系)
  • String 的 intern() 方法(把字符串丢到字符常量池中)
  • new String() 创建了几个对象?
  • 不同版本的 intern() 使用

JVM 垃圾回收部分

Java JVM学习-垃圾回收相关概念
这篇博客是一些零散的知识点,具体看下面的各小结:

  • 内存溢出的原因(Java 虚拟机的堆内存设置不够、代码中创建了大量大对象、创建了大量的字符串)
  • 内存泄漏是啥?(单例模式、需要 close 的资源未关闭(例如 Socket、Database))
  • Stop The World 是什么?(指的是 GC 事件发生过程中,会产生应用程序的停顿)
  • System.gc() 真的执行了吗?
  • 垃圾回收器 的并发与并行
  • 安全点(Safepoint)和 安全区域(Safe Region)
  • 对象的 finalization 机制 ⛔
  • 强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)⭐

Java JVM学习-堆的 GC 与调试工具 ⭐
这篇笔记主要记录了如何查看 GC,以及各种调试工具

  • 不同 GC 阶段的区别
  • GC 日志分析
  • jps 查看所有 Java 进程
  • jstat 监视虚拟机各种运行状态信息
  • jinfo 实时地查看和调整虚拟机各项参数
  • jmap 生成堆转储快照
  • jhat 分析 heapdump 文件
  • jstack 生成虚拟机当前时刻的线程快照
  • JDK 可视化分析工具 ⭐

Java JVM学习-垃圾回收相关算法
主要介绍了 GC 标记阶段 和 清除阶段 这两个阶段使用的算法:

  • 什么是 GC?(哪些内存需要回收?什么时候回收?如何回收?什么是垃圾(Garbage)呢?)
  • 垃圾回收哪些区域呢?(频繁收集 Young 区、较少收集 Old 区、基本不动 Perm 区)
  • 标记阶段:引用计数算法 和 根搜索算法(可达性分析)⭐
  • 清除阶段:标记-清除算法 ⭐
  • 清除阶段:复制算法(最快,适用于 年轻代 的垃圾回收)⭐
  • 清除阶段:标记-压缩算法(对 标记-清除算法 的改进,但是速度是最慢的,适用于老年代的垃圾回收)⭐
  • 增量收集算法(逐步 GC 的思想)
  • 分区算法(G1)

Java JVM学习-垃圾回收器
这篇主要介绍了各种垃圾收集器的优缺点,以及如何选择

  • 垃圾回收器的分类方式
  • 评估垃圾回收器的性能指标(吞吐量和暂停时间的权衡)
  • Serial 回收器:串行回收(单线程的垃圾回收器,年轻代采用复制算法,老年代采用标记-压缩算法)
  • ParNew 回收器:并行回收(多线程版本的 Serial 回收器)
  • Parallel 回收器:吞吐量优先(在 Java8 中,默认是此垃圾收集器,与上面那个区别就是吞吐量优先) ⭐
  • CMS 回收器:低延迟(第一次实现了让垃圾收集线程与用户线程同时工作,但是无法和 Parallel 一起使用)
  • CMS 的四个阶段(初始标记、并发标记、重新标记、并发清除) ⭐
  • G1 回收器:区域化分代式(采用分区算法,把堆内存分割为很多不相关(物理上不连续的)的区域)
  • 垃圾收集器的组合关系(如何选择合适的垃圾回收器)
  • GC 日志分析

IO 部分

Java IO学习-字节流 和 Java IO学习-字符流 ⭐
这个没啥好说,BIO 的基础,主要知识点:

  • 文件流 ⭐
  • 序列化 serialVersionUID 验证版本一致性
  • PipedInputStream 管道(主要用于线程之间的通信,之后线程通信那篇会详细讲)
  • 缓冲流(主要理解内部 buffer 和外部 buffer 的区别)⭐

Java IO学习-打印流 ⛔
这个主要了解一下就行了,如果想要实现一个自己的日志框架之类的可以看一下里面的 “改变打印流向”

Java IO学习-File、Files、Path工具类
主要的文件操作工具类(例如递归删除之类的)
主要知识点:

  • Java 资源路径的问题

下面开始 NIO 的部分了

Java IO学习-NIO 与 BIO 各种概念及区别
这篇主要介绍 NIO 和 BIO 的区别(Stream 与 Channel 的区别)
主要知识点:

  • Stream 与 Channel 的区别(主要就是理解发布订阅模式)
  • 多路复用(搭配 Linux IO 基本概念学习(IO 多路复用) 观看)⭐
  • 零拷贝(搭配 零拷贝技术是什么? 观看)⭐

Java IO学习-NIO 文件编程
这篇没啥重要的,主要介绍了一下 NIO 的零拷贝 API,以及文件传输咋用
主要知识点:

  • transferTo 方法(零拷贝)
  • 文件大于 2G 的传输(文件过大就不适合零拷贝了,所以需要将其分片传输)

Java IO学习-NIO 核心组件及基本概念
这篇主要介绍了一下 NIO 的三大组件(Channel、Buffer、Selector)的关系
主要知识点:

  • Selector 选择器(顺便介绍了使用线程池来维护连接的优缺点)
  • Buffer 缓冲区(主要介绍这个 NIO 的核心容器的工作原理) ⭐

Java IO学习-NIO 粘包与半包 ⛔
这篇了解就好,主要介绍了传输时会遇到的粘包与半包问题,以及如何解决它

Java IO学习-NIO 网络编程
这篇主要介绍了一下原生的 NIO 如何进行网络编程,以及 Selector 是如何处理事件的
主要知识点:

  • Selector 多路复用(各种事件的处理方式)
  • 消息边界问题(就是上面 粘包与半包 问题的实际解决实例)

Java IO学习-NIO 网络编程(多线程优化)
看名字也知道,与上面那篇是姐妹篇,主要使用多线程进行优化,主线程配一个选择器(Boss),专门处理 accept 事件,以及创建工作线程(Worker),每个线程配一个选择器,轮流处理 read 事件

网络部分

⚽ Java HTTP编程 ⛔
主要介绍了一下 Java 的原生的 HTTP 请求工具

  • JDK11 提供的 HttpClient
  • 常用的第三方 HttpClient 工具
  • URL 工具类

Java Servlet 学习之环境配置 ⛔
简单的介绍了下如何配置 Servlet 环境

  • Servlet、Server 和 Service 的区别
  • 使用嵌入式 Tomcat 开发

⚾ Java Servlet 学习之工作流程
一个 Servlet 生命周期的各个部分

  • Servlet 生命周期
  • Servlet 编写过滤器
  • 过滤器和 Spring的拦截器的区别

Java TCP 编程

  • Socket 是啥?
  • TCP实现聊天室
  • 简单实现 HTTP 协议

Java UDP编程

  • 如何使用 UDP 通信
  • 多线程实现聊天室

Netty 部分(因为使用不多,所以这部分待完善)

Java Netty 各组件的作用
Netty 的纵览,搞懂各个组件的作用是后面使用 Netty 的关键

  • Channel 接口
  • EventLoopGroup 和 EventLoop 的关系
  • ChannelHandler 和 ChannelPipeline 的关系
  • 引导程序 Bootstrap

Java Netty 的基本使用
如何使用 Netty

Java Netty 事件循环对象 EventLoop

  • EventLoopGroup 和 EventLoop 关系图
  • 处理普通与定时任务
  • 处理 IO 任务
  • 增加多个 Worker Group 处理不同的事件

Java Netty 通道 Channel

Java Netty 传输工具 ByteBuf

  • 为什么需要 ByteBuf?

Java Netty 提供的几种传输包

  • NIO 非阻塞 IO
  • Epoll 用于 Linux 的本地非阻塞传输
  • 用于 JVM 内部通信的 Local 传输
  • Embedded 传输
  • 各种传输的应用场景

Java Netty 使用 WebSocket

  • 如何支持 WebSocket
  • 处理 HTTP 请求
  • 处理 WebSocket 帧

集合相关

Java 集合类学习 通用接口
主要就是两个对象的比较接口的区别,继承 Comparable 这个接口后无需使用定制排序,直接默认调用排序接口就行了(自然排序),而 Comparator 接口主要用于定制排序
主要知识点:

  • Collection 集合接口(就是一些各个集合类都有的通用方法)
  • 迭代器的使用(Iterator) ⭐
  • 对象的比较(Comparable 接口和 Comparator 接口的区别)

Java 集合类学习 常用工具类
介绍了两个主要的操作集合和数组的工具类,经常使用
主要知识点:

  • Collections 工具类(主要是包装一下集合类的工具,例如 同步控制、设置不可变集合)
  • Arrays 工具类(主要就是数组转集合的操作,其中需要注意如何基本类型包装成集合)

Java 集合类学习 List 集合
主要介绍了一下 List 接口,以及 ArrayList 和 LinkedList 的结构
主要知识点:

  • List 接口主要的实现类
  • ArrayList 原理部分(主要看扩容机制)⭐
  • LinkedList 底层的数据结构是基于双向循环链表(它同时是 Deque 接口的实现类)
  • CopyOnWriteArrayList(线程安全的 List 集合)

Java 集合类学习 Deque 双端队列 ⛔
上接上面的 LinkedList,双端队列。Deque 既可以用作后进先出的栈,也可以用作先进先出的队列。主要看看如何使用

Java 集合类学习 Queue 队列 ⭐
主要介绍了一下阻塞队列的使用,然后拓展非阻塞队列(注意,队列实现类除了 PriorityQueue 都是线程安全的)

  • add 和 offer 插入的区别
  • element 和 peek 查看的区别
  • remove 和 poll 出队的区别
  • 所有队列实现类一览
  • 常用的阻塞队列实现类(ArrayBlockingQueue)
  • 阻塞队列是如何保证线程安全的?(入队出队同一把锁)

Java 集合类学习 PriorityQueue ⛔
PriorityQueue 就是堆这种数据结构在 Java 的实现类,一般用在一些算法问题上(例如:最小的 K 个数),补充:堆在 Java 中扩容是直接 原数组长度 * 2,所以插入 n 条元素就需要扩容 O ( l o g n ) O(logn) O(logn)
搭配以下文章食用:

  • 数据结构 Heap 堆
  • 高级排序算法 堆排序

Java 集合类学习 Set 集合
Set 集合与 List 集合的区别就是,Set 集合的元素不能重复,而且无法保证顺序(有顺序的叫做 SortedSet),Set 实际上相当于只存储 key、不存储 value 的 Map。
主要知识点:

  • HashSet 底层就是 HashMap,两者的工作方式是一样的
  • TreeSet 是 SortedSet 接口的唯一实现类,TreeSet 可以确保集合元素处于排序状态。(它内部实现就是 TreeMap)

Java 集合类学习 Map 集合
这篇主要介绍了一下常用的 Map 实现类,常用的 Map 有哪些,哪些场景应该使用哪种实现类
主要知识点:

  • LinkedHashMap 的原理
  • TreeMap 是 SortedMap 这个接口的唯一实现类(TreeMap 内部也是红黑树,所以它的效率并不低)
  • 如何使 Map 线程安全?(主要介绍介绍了 synchronizedMap 方法的原理)

Java HashMap 和 HashTable
HashMap 的原理几乎是面试必问的,所以这篇挺重要的。文章主要介绍了一下 HashMap 的实现原理,以及 JDK7 和 JDK8 它发生的变化。
主要知识点:

  • Java 中的 HashCode(介绍了为什么需要重写 hashcode 方法,以及它是如何和 equals 配合工作的)
  • JDK1.7 中的实现的结构(主要就是链表,以及并发场景下环形链表的死循环问题)
  • JDK1.8 中的实现的结构(链表红黑树,各个默认参数的作用)
  • 如何初始化 HashMap(loadFactor 加载因子,threshold 扩容阈值是如何使用的)
  • 为何 HashMap 的数组长度一定是 2 的次幂?(使用 & 代替 % 操作,提高性能)
  • 为什么需要使用 “扰动函数”(高低位互换,减少碰撞)
  • 哈希桶数组如何扩容
  • HashTable 和 HashMap 的区别(HashTable 是锁全表)

Java 集合类学习 ConcurrentHashMap
这个和上面是一起考的,主要考察JDK7 和 JDK8 的区别。

  • 值使用 volatile 关键词修饰,保证了内存可见性,所以每次获取时都是最新值。
  • JDK1.7 中的实现的结构(Segment 分段锁,每个 Segment 就是一个子 HashMap)
  • JDK1.8 中的实现的结构(锁单位从 Segment 变成只锁定当前链表或红黑二叉树的 首节点)
  • JDK1.8 费时操作(扩容这种)采用 synchronized,修改值这种采用 CAS 操作

并发操作

Java 并发编程-啥是线程
主要介绍了线程的几种状态和如何切换的

  • 并发与并行的区别
  • 线程与进程有什么区别?
  • 守护线程和普通线程的区别?
  • 上下文切换的原理(主要解释了程序计数器为什么是私有的)
  • 线程 5 个状态(创建状态、运行状态、阻塞状态、就绪状态、死亡状态)

Java 并发编程-核心理论
主要介绍了并发编程中的常见理论,重点看 “有序性”、“原子性”、“可见性” 这三个并发编程的重要特性

  • 有序性(即程序执行的顺序按照代码的先后顺序执行,因为可能会出现指令重排序)
  • 原子性(原子性是指一个操作是不可中断的,要么全部执行成功要么全部执行失败,有着 “同生共死” 的感觉)
  • 可见性(一个线程修改了这个变量的值,其他线程能够立即看得到修改的值)
  • 共享性(就是同个资源的共享,也是线程安全的主要原因之一)
  • 互斥性(指同时只允许一个访问者对其进行访问,具有唯一性和排它性)

Java 并发编程-JMM 概念
理解 Java 内存模型(Java Memory Model,JMM)是后面学习各种锁的关键,例如内存不可见问题引申出了 volatile 关键词,运行时内存的划分知道了 JVM 哪些部分是私有的,哪些部分是公有的。

  • 什么是 JMM?(就是 JVM 为了屏蔽各个硬件平台和操作系统的内存(RAM)访问差异的设计)
  • 共享内存并发模型 和 消息传递并发模型区别(就是分布式锁那种和普通的本地锁的联系)
  • 运行时内存的划分(解释了哪些部分是公有的,哪些部分是私有的)
  • 为什么在堆中会有内存不可见问题?(Java 是先访问缓存区再访问内存的,所以这里会有一个不同步的问题)
  • JMM 是如何保证原子性的?(提供的 8 种原子操作)

Java 并发编程-缓存一致性问题 ⛔
与上面是姐妹篇,但是这篇很多知识点并不完善,而且也太过底层,我自己也不确定讲述的是否正确,所以这篇笔记暂时先这样,以后学习到更多的知识再更新

  • 为什么会导致缓存一致性问题?(多核 CPU 中,每条线程可能运行于不同的 CPU 中)
  • 缓存一致性协议 MESI(CPU 如何更新 Cache 里面的共享变量)
  • MESI 缓存的延迟问题(MESI 并不是完全保证 Cache 里面的变量和内存的变量一致)
  • 缓存一致性和多线程同步的关系

Java 并发编程-多线程基础使用
主要介绍了一下基本的多线程接口

  • Thread 类 和 Runnable 接口的使用
  • Callable、Future 与 FutureTask 取得多线程任务的返回值(概念就像 Netty 的那个一样)
  • 实现 Runnable 接口和 Callable 接口的区别
  • 执行 execute()方法和 submit()方法的区别是什么呢?
  • 运行时操作线程的方法(重点关注 yield、join 方法,它们可以用来线程同步)⭐
  • 线程组(使用线程组可以对线程进行批量控制)

Java 并发编程-各种锁的概念
这篇笔记主要是下面学习的各种锁的基础,理解什么场景应该使用什么锁的关键

  • 共享锁和排他锁的概念(比较多的出现在数据库的事务当中)
  • 乐观锁与悲观锁的概念(synchronized 关键字和 Lock 的实现类都是悲观锁,乐观锁主要就是 CAS 自旋算法)
  • 公平锁和非公平锁(主要区别就是是否去排队)
  • 自旋锁 和 自适应自旋锁(自适应自旋锁就是自旋锁的一个升级版,它的自旋时间是根据上一个持有该锁的线程的自旋时间确定的)
  • 可重入锁和非可重入锁(重入锁允许锁和多个方法绑定,必须把这些绑定的方法全部执行完成才会释放锁)
  • 死锁与预防(应该如何避免死锁呢?答案是:线程获取锁的顺序要一致)
  • 活锁(多线程中出现了相互谦让)
  • 线程饥饿(就是某个线程一直占着资源,导致其它线程一直得不到执行)
  • 分布式锁(通过 redis、zookeeper 等中间件来实现的分布式锁)

Java Unsafe类
这个算是 Java 中各种乐观锁以及原子操作的基石

  • 取得 Unsafe实例
  • 线程的挂起和恢复(主要是 LockSupport 工具类的基石)
  • CAS 机制(自带的 CAS 原子操作)

Java 并发编程 CAS 乐观锁
主要介绍一下 CAS 乐观锁的原理

  • CAS 的概念
  • CAS 是怎么工作的
  • ABA 问题 ⭐

Java 并发编程-通信
一般经常考察的多线程使用都涉及到线程之间的通信,那有多少种方法呢?这篇就对这些操作进行了一次汇总

  • synchronized 方法导致的死锁(获取锁的顺序不对导致的死锁,这一节主要是用来引出下面的下面的信号量机制)
  • wait / notify 机制(wait 释放自己获取的锁,notify 唤醒等待的线程)
  • 生产消费-虚假唤醒的问题(针对上面的 wait / notify 机制产生的问题)
  • Lock 接口下的 wait / notify 工具类 Condition 监视器
  • Semaphore 信号量工具(令某一时刻只允许规定数量的线程执行)
  • LockSupport 线程的阻塞和唤醒(Lock 接口挂起和唤醒线程的工具类)⭐
  • 使用 volatile 实现信号量(主要利用它的实时性)
  • 管道流:多线程传输数据(用到再补充) ⛔
  • 多线程顺序打印 “ABCABC” (介绍的四种方法基本上复习了一遍上面的工具类)

Java 并发编程-并发包下的工具类
这里介绍一下常用的并发编程工具,其实部分内容和上面 通信 那里讲的有点重合了,但是这里主要是汇总使用

  • CountDownLatch 计数(实现类似计数器的功能,要注意的是,它是一次性的,设置的计数用完就不能关上了)
  • CyclicBarrier 回环栅栏(让一组线程等待至某个状态之后再全部同时执行后面的状态)
  • Semaphore 信号量(令某一时刻只允许规定数量的线程执行)
  • Condition 监视器(就是 Lock 包下的 wait / notify 工具)
  • LockSupport 线程的阻塞和唤醒(主要作用是挂起和唤醒线程,该工具类是创建锁和其他同步类的基础)⭐
  • ScheduledThreadPoolExecutor 定时任务(搭配后面的线程池使用)

Java 并发编程-synchronized关键字
这个 synchronized 关键字可以说是 Java 并发编程的第一颗了,使用它是很简单,但是要理解原理还是有很多知识点的

  • 对象锁是啥?
  • 锁包装类的坑(主要是值缓存以及每次拆装箱创建对象导致 Lock 不可靠)
  • synchronized 锁升级的流程
  • 偏向锁(只有一个线程使用这个锁时才是偏向锁,一旦出现第二个线程使用这个资源,马上升级为轻量锁)
  • 轻量锁的加锁(这个 CAS 采用适应性自旋,CAS 尝试多次后依旧无法取得锁后,那马上升级为重量锁)
  • synchronized 和 ReentrantLock 的区别

Java 并发编程-Lock 接口及其相关工具类
主要介绍一下 Lock 接口下的实现类,其实这里没有完全写完,关于 ReentrantLock 的部分太简陋了,以后再更新…

  • Lock 接口是啥?(早期 synchronized 并不完美,所以为了方便并发编程,创建了一个 API 级别的锁控制)
  • ReadWriteLock 接口(读锁、写锁接口)
  • Lock 接口的主要实现类 ReentrantLock 锁 ⭐
  • ReadWriteLock 接口的主要实现类 ReentrantReadWriteLock 锁

Java 并发编程-volatile关键字
这个关键字的学习应该联系上面的 JMM 一起食用,主要是为了解决指令重排和内存可见性的问题

  • 内存可见性问题
  • volatile 无法保证原子性
  • volatile 防止指令重排

Java 多线程-Atomic 原子操作类
保证原子操作的类型,即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。

  • Atomic 原子操作的原理
  • JUC 包中的原子类是哪 4 类

Java 并发编程 AQS 同步队列
AQS 是 AbstractQueuedSynchronizer 的简称,即抽象队列同步器,它是 Lock 各个实现类的关键,用它可以配置多个线程竞争资源时是以何种策略取得资源的。

  • AQS 的概念
  • AQS 定义两种资源共享方式 ⭐
  • 申明自己的 AQS 类(原理向)⛔

Java 多线程-ThreadLocal 的使用及原理
ThreadLocal 类可以给每个线程维护一个独立的变量副本,使多线程的场景使用共有的 ThreadLocal 变量,同时每个线程在 ThreadLocal 对象中保存的变量副本是相互隔离的。

  • ThreadLocal 线程局部变量的使用方法
  • 实现原理(内部维护了一个弱引用的 ThreadLocalMap)
  • 弱引用造成的内存泄漏(所以用完要 remove)⭐
  • ThreadLocalMap 的 value 为什么是强引用

线程池

Java 并发编程-线程池 ThreadPoolExecutor
ThreadPoolExecutor 是线程池的主要工具类

  • ThreadPoolExecutor 的原理(任务提交后是如何调度执行的)
  • 线程池的状态
  • ThreadPoolExecutor 的重要参数
  • ThreadPoolExecutor 饱和策略
  • 线程池获取返回结果
  • FixedRate 和 FixedDelay 区别 (前者是以固定时间间隔触发,不管任务执行多长时间,后者是执行完后隔多长时间再次执行)

Java 多线程-线程池 submit 和 execute 方法
主要介绍了一下线程池如何取得返回值

Java 多线程-线程池 Executors 工具类
因为 ThreadPoolExecutor 参数太多,Executors 就是提供的默认的策略(用静态工厂模式)

  • newSingleThreadExecutor 单线程的线程池
  • newCachedThreadPool 无限线程的线程池
  • newFixedThreadPool :创建固定大小的线程池
  • ScheduledThreadPool 定时任务

Java 多线程-线程池 任务调度机制 ⛔
线程池的任务调度机制,对上面 ThreadPoolExecutor 这块的补充

  • 任务缓冲(就是阻塞队列的工作原理)
  • 任务申请
  • 任务拒绝(就是上面的饱和策略)
  • Worker 线程执行任务
  • Worker 线程增加
  • Worker 线程管理
  • Worker 线程回收

Java 多线程-线程池之异步任务 ⛔
利用线程池实现一个简单 事件管理器

JDK8 新特性部分~

JDK8 之后的新特性记录

  • var 关键字
  • try-with-resources 语句
  • JDK9 提供的 of 方法
  • 单个 catch 块中处理多个异常
  • Collection#removeIf() 方法删除满足特定条件的元素

Lambda 函数式接口

  • 匿名类 与 Lambda 区别
  • Lambda 的 this 指针 ⭐
  • 常用的函数式接口
  • 双冒号(::)方法引用 ⭐

Java Stream 流式编程 ⭐
这个就是入门 Lambda 编程的第一步,因为经常用来操作集合,所以还是研究下
重点关注:

  • 流的特点(装饰器模式,惰性计算)
  • map 映射新值
  • groupBy 分组

Java Optional 使用
主要用于非空判断

  • Optional 是什么?
  • 如果不为空执行方法⭐
  • 如何正确使用 Optional

Java 常用工具包

Hutool 工具库
Hutool 是一个 Java工具类库,通过静态方法封装一些常用的方法

Java 的 JSON 解析库 Jackson 学习
用来序列化和反序列化 JSON 的 Java开源框架

日志大礼包:

  • 日志工具–LOG4J
  • 日志工具 Commons Logging
  • SLF4J 接口和 Logback

Lombok 常用方法

JUnit 编写单元测试

数据库

MySQL

MySQL 的基本使用

MySQL 基本增删改
基本的增删改查如何写

  • 清空表(truncate)使用 delete 的方式清空表数据有个缺点,就是索引不是从零开始,所以这时就需要使用这个 truncate 关键字来清空表了
  • 复制表数据

MySQL 的查询语句~

  • 查询语句的执行顺序
  • 分组后的筛选(having 关键字是对 group by 之后的结果进行筛选)
  • limit 关键字的妙用~(限制结果数量)
  • 联合查询

MySQL 索引的使用~

  • 索引的分类(主键索引、唯一索引、普通索引、全文索引、联合索引)
  • 显示指定表使用 BTREE 索引
  • 最左前缀匹配原则
  • 选择区分度高的列作为索引
  • 索引列不能参与计算
  • 修改优先拓展(尽量的扩展索引,不要新建索引)

MySQL 约束和级联操作 细节看: MySQL 学习(12)约束与触发器
常用约束

  • 自增长列
  • 主键约束、外键约束
  • 级联更新与删除

MySQL 学习(13)视图和分区表

  • 视图是什么?(主要用途之一是被用做一个抽象,方便使用,它本身不会提高性能)
  • 分区表的创建(注意看它的缺点)

MySQL 的原理

MySQL 学习(1)体系结构
对 MySQL 的整体有个认识

  • MySQL 是由哪些结构构成的
  • 一条 SQL 语句是如何执行的
  • 各个存储引擎层的区别

MySQL 学习(2) InnoDB 体系结构
对 InnoDB 的结构有个认识

  • Master 线程(核心的后台线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性)
  • IO 线程(主要用来处理 AIO 的回调函数)
  • Purge 线程(事务被提交后,其所使用的 undolog 可能不再需要,因此需要 PurgeThread 来回收已经使用并分配的 undo 页)
  • 缓冲池是什么?(把页放在 cache 中)
  • 自适应哈希索引(会自动创建)
  • InnoDB 是如何管理 Cache 的?(通过 LRU (Latest Recent Used,最近最少使用)算法来进行管理)⭐
  • 保护热点数据(避免大表扫描等操作对热点数据的影响(避免被挤出 LRU 中))⭐
  • 脏页的概念(dirty page)

MySQL 学习(3) CheckPoint 技术 ⛔
Checkpoint(检查点)用于将缓冲池中的脏页刷回到磁盘,Checkpoint 技术的目的是解决以下几个问题:缩短数据库的恢复时间;缓冲池不够用时,将脏页刷新到磁盘;重做日志不可用时,刷新脏页。但是如何挑选一个合适的时机执行 Checkpoint 呢?

  • CheckPoint 发生的时机

MySQL 学习(4) Master Thread 的工作 ⛔
Master thread 是核心的后台线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插入缓冲、undo 页的回收等。因为暂时没有学到这方面的知识,所以这篇博客待更新…

MySQL 学习(5)InnoDB Insert Buffer(插入缓冲) ⛔
Insert Buffer 就是用于 提升非聚集索引页 的插入性能的(因为通过聚集索引查找到的非聚集索引不是顺序存储的,这样会导致随机访问的出现,从而导致插入操作性能下降),对于非聚簇索引的插入或者更新操作,不是每一次都直接插入到索引页中,而是先判断插入的非聚集索引是否在缓冲池中,若在,则直接插入;若不在,则先放入到一个 Insert Buffer 中。

MySQL 学习(6)Innodb Double Write ⛔
在应用重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是 doublewrite。

MySQL 学习(7)自适应哈希索引和异步 IO
InnoDB 存储引擎会监控对表上各索引页的查询。如果观察到建立哈希索引可以带来速度提升,则建立哈希索引,称之为自适应哈希索引(Adaptive Hash Index, AHI)。(无法自己创建,InnoDB 自己维护的)

  • 自适应哈希的建立条件

MySQL 学习(8)MySQL 中的文件
主要介绍了一下 MySQL 中各种文件的作用

  • 表结构定义文件 frm
  • 错误日志
  • 慢查询日志(slow query log),需要自己手动启动
  • 查询日志(general log)
  • 重做日志(redo log)用于确保事务的持久性(redo 日志记录事务执行后的状态)。
  • 二进制日志(binlog),在主从复制中,从库利用主库上的 binlog 进行重播,实现主从同步
  • 回滚日志(undo log),将数据从逻辑上恢复至事务之前的状态

MySQL 学习(9)表空间、区、页 ⛔

  • 索引组织表的概念(数据即索引,索引即数据)
  • InnoDB 逻辑存储结构(表空间由 段、区、页 组成)
  • 段 segment(就是保存索引组织的,因为数据即索引,索引即数据)
  • 区 extent(存储页的单位,一个区一共有 64 个连续的页)
  • 页 page(页是 InnoDB 磁盘管理的最小单位)

MySQL 学习(10)数据行结构和行溢出机制 ⛔

  • ROW_FORMAT 是干什么的?
  • 静态表和动态表的概念
  • 紧凑的行格式长啥样?
  • Compact 格式是如何做到紧凑的?
  • DYNAMIC 格式是怎么存储的?

MySQL 的数据页 详细看:MySQL 学习(11)数据页结构 ⛔

在 InnoDB 存储引擎中,数据页是 InnoDB 磁盘管理的最小的数据单位,数据页的默认大小为 16KB,这里介绍一下这个数据页的结构

  • 数据页长啥样?
  • 数据页分裂问题(页分裂的目的就是保证:后一个数据页中的所有行主键值比前一个数据页中主键值大)

(Next-Key Lock):是记录锁与间隙锁的组合

MySQL 学习(14)索引的结构和联合索引的原理

  • 为什么使用 B+ 树,不使用其它数据结构?
  • MyISAM 的 B+ 树结构和 InnoDB 的区别
  • 聚集索引 VS 非聚集索引(顺便理解了为啥要避免回表操作)
  • 联合索引是什么?(理解:最左前缀匹配原则)

MySQL 学习(15)是否使用索引判断、回表、索引覆盖
索引即数据,数据即索引

  • 什么时候需要创建索引?
  • 使用索引查询一定能提高性能吗?(INSERT,DELETE,UPDATE 将为此多付出 4,5 次的磁盘 I/O)
  • 回表查询与索引覆盖是什么?(索引覆盖:从索引中就可以得到查询结果,从而不需要查询聚簇索引中的行数据信息)
  • 判断一条语句是否用到索引覆盖

MySQL 学习(16)联合索引的原理和最左前缀匹配原则
索引的具体使用说明

MySQL 学习(17)意向锁(表锁)、MVCC、Next-Key Lock

  • 一致性锁定读(手动加锁)
  • 意向锁是什么(表锁)?
  • 一致性非锁定读与 MVCC ⭐
  • 快照读与当前读 ⭐
  • 行锁的三种算法
  • RR 级别是否解决了幻读

补充上面 MySQL 中的锁
主要介绍了一下 MySQL 的各种锁

  • 共享锁和排他锁(行级别的锁)
  • 意向锁
  • InnoDB 行锁实现方式(通过给索引上的索引项加锁来实现的,所以只有通过索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁)
  • 记录锁(Record Lock):它封锁索引记录,作用于唯一索引上
  • 间隙锁(gap lock):作用于非唯一索引上,主要目的,就是为了防止其他事务在间隔中插入数据,以导致 “不可重复读”(加了间隙锁之后,在范围区间内数据不允许被修改和插入。从而避免了在范围查询时出现脏读、重复读、幻读问题)
  • 临键锁

补充上面 MySQL 学习(17-1)什么时候需要手动加锁
其实这篇说了这么多主要讨论:RR 是否解决了幻读?(使用 lock in share mode 让 RR 加上间隙锁,从而解决幻读)

MySQL 学习(18)锁的问题:脏读、不可重复读、丢失更新、死锁
这篇讨论了一下并发带来的问题

  • 脏读:在不同的事务下,当前事务可以读到另外事务未提交的数据,简单来说就是可以读到脏数据 ⭐
  • 不可重复读取:脏读是读到未提交的数据,而不可重复读读到的却是已经提交的数据 ⭐
  • 逻辑意义的丢失更新问题(其实就是应用程序没有读取到最新的数据就直接覆盖了,应该使用串行化来解决)⭐

MySQL 学习(19)事务的分类与实现

  • A 原子性(atomicity):要么都做,要么都不做 ⭐
  • C 一致性(consistency):如果事务中某个动作失败了,系统可以自动撤销事务一返回初始化的状态 ⭐
  • 隔离性(isolation):事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,即该事务提交前对其他事务都不可见 ⭐
  • D 持久性(durability):事务一旦提交,其结果就是永久性的 ⭐
  • 扁平事务(在扁平事务中,所有操作都处于同一层次)
  • 带有保存点的扁平事务(分段提交)
  • 嵌套事务:任何子事务都在顶层事务提交后才真正的提交
  • 分布式事务
  • 并行事务的原子性
  • redolog 重做日志:重做日志用来实现事务的持久性,即事务 ACID 中的 D。 ⭐
  • binlog 二进制日志:其用来进行 POINT-IN-TIME(PIT)的恢复及主从复制(Replication)环境的建立
  • redo log 和 binlog 区别(redo log 是属于 innoDB 层面,binlog 属于 MySQL Server 层面的)
  • undolog 回滚日志(保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读) ⭐

MySQL 笔记杂项

MySQL 常用函数学习
常用的工具函数

  • 分组函数
  • 字符函数
  • 数学函数
  • 日期函数
  • 工具函数
  • 系统函数(查看系统信息)
  • 流程控制函数(case 语句)
  • 自定义函数 ⭐
  • 触发器

MySQL 常见的数据类型
各种数据类型的选择(在阿里的开发手册里面是如何选择的)

  • 整型(使用 unsigned 来设置无符号)
  • 浮点型(小数类型为 decimal,禁止使用 float 和 double)
  • 日期型(timestamp 会和实际时区挂钩)
  • 二进制

MySQL 用户管理
操作用户一般是 DBA 的职责,可以通过角色系统来管理权限

  • 常用的操作用户操作

MySQL 使用 Explain 分析优化实例
查询优化工具 explain 命令
具体的使用示例:MySQL 学习(0)优化的核心 explain 执行计划

MySQL 数据库备份与恢复
为了避免误操作,定期备份和恢复数据还是有必要学习的

  • 备份:从数据库导出数据
  • 恢复导入数据库数据
  • 开启 logbin(binlog 备份)

MySQL 常见场景题
就是 SQL 题的记录,也没有啥特别难的,复习一下 “困难题” 就好了

MySQL 学习(20)分布式事务

  • 基于 XA 协议的两阶段提交
  • 消息事务 + 最终一致性

MySQL 学习(21)数据库优化

  • 选择合适的 CPU(使用多核 64 位 CPU)
  • 内存的重要性(越大越好,因为需要 Cache)
  • 硬盘对数据库性能的影响(机械硬盘有两个重要的指标:一个是寻道时间,另一个是转速)
  • 数据库结构优化(增加中间表、增加冗余字段、使用自增 ID)

Redis

Redis 配置环境和操作数据常用命令
这篇笔记主要就是记录常用的数据结构以及在控制台如何使用它们

Redis 的单线程和多线程

  • Redis 只有单线程吗?(选择性 使用多线程模型,注意 AOF 是多进程不是多线程)
  • I/O多路复用技术 ⭐
  • 选择单线程的核心原因(Redis 并不是 CPU 密集型的服务) ⭐
  • 单线程的 Redis 为何高并发快 ⭐

Redis 各种数据结构的使用场景 ⭐

  • String 的使用场景(数据库缓存、阅读量,播放量计数、共享 Session、IP 限速)
  • Hash 的使用场景(维护一个简单的数据表,但是这种数据表只适合索引查询,不适合范围查询)
  • 列表 List 使用场景(消息队列,利用 BLPOP 阻塞式列表的弹出原语、维护一个栈、分页获取文章列表)
  • 集合 Set 的使用场景(用户标签 Tag(交并集)、抽奖功能(随机取列表))
  • 有序集合 ZSet 的使用场景(排行榜、延迟消息队列)

Redis 缓存读写策略设计及常见问题
这篇笔记主要记录 Redis 当 MySQL 缓存层的常见问题

  • 缓存数据的处理流程是怎样的?
  • 缓存更新策略(LRU/LFU/FIFO算法剔除、超时剔除、主动更新)⭐
  • 缓存粒度控制 ⭐
  • 缓存雪崩(采用了相同的过期时间) ⭐
  • 缓存击穿(缓存击穿是某个热点的 key 失效,大并发集中对其进行请求)⭐
  • 缓存穿透(用户查询数据,在数据库没有,自然在缓存中也不会有)⭐
  • 缓存预热 ⭐
  • 缓存降级(缓存失效或缓存服务器挂掉的情况下,不去访问数据库,直接返回默认数据或访问服务的内存数据)⭐
  • 旁路缓存模式
  • 读写穿透模式
  • 搭配 Nginx 设计的缓存机制

Redis 各种数据结构的内部原理

  • 基本结构 redisObject
  • String 类型(SDS(动态字符串))
  • List 类型(双向链表、压缩列表)
  • 散列(Hash)类型(字典、压缩列表)
  • Set 类型(如果是整数类型,就直接使用整数集合 intset 使用二分查找来辅助,如果不是整数类型就使用字典)
  • ZSet 类型(跳跃表、压缩列表)

Redis 实战:根据投票排序功能

  • 利用 ZSet 类型排序文章
  • 文章分组:利用给文章加 Tag 并利用交并集来分组

Redis 实战:Web 应用

  • 令牌 Cookie(创建一个守护线程,专门用来清理 Tokens)
  • 购物车功能(使用散列存储 商品 ID 与商品订购数量之间的映射)
  • 网页缓存(对页面缓存)
  • 网页分析(根据浏览次数对商品进行了排序)

Redis 事务的基本使用
Redis 的基本事务(basic transaction)需要用到 MULTI 命令和 EXEC 命令,这种事务可以让一个客户端在不被其他客户端打断的情况下执行多个命令(原理是乐观锁 CAS)。

  • Redis 事务命令
  • watch 监控事务(乐观锁 CAS)⭐
  • 为什么需要事务?
  • 管道的使用(事务)
  • 非事务型流水线(提高性能) ⭐

Redis 实战:使用事务构建一个游戏商城

  • 定义用户信息和商品信息(利用 Hash 维护一个简单的数据表)
  • 将商品放到市场上销售和购买商品(使用事务的示例)

Redis 实战:构建分布式锁

  • 乐观锁的导致问题(冲突过多,导致重试的次数也过多)
  • 锁设计时需要考虑的问题 ⭐
  • 构建一个基本的锁 ⭐
  • 带有超时的锁 ⭐

Redis 持久化数据 ~

  • RDB 方式,使用内存快照的方式
  • AOF 方式,把命令写到日志文件里

Redis 客户端 Jedis 学习
没啥好说的,就是这个 Jedis 常用方法介绍

MyBatis

MyBatis 配置文件 以及 Mapper 的写法 ⛔
简单介绍了一下 Mapper 的写法(有点过时了)

  • 配置项的编写顺序
  • 读取 properties 文件
  • 返回自增 ID ⭐
  • 日志工厂

MyBatis 动态 SQL
如题:MyBatis 如何实现动态 SQL

  • if 语句
  • “switch” 语句
  • 动态 Where 关键字
  • trim 动态修改(动态匹配 AND 或者 OR 关键字,或者自动加 ( )
  • 动态 Set 语句
  • 遍历传入的数组

MyBatis 关系映射及多表查询 ⭐

  • 表与表之间的关系类型(一对一、一对多、多对多)
  • association 以及 collection 标签(前者 一对一关联、后者 一对多关联)
  • 懒加载的原理(所以不一定使用这种嵌套查询效率就低)⭐

MyBatis 分页
主要介绍的是 MyBatis Plus 的分页,原理其实就是通过 AOP 自动在 SQL 加上 limit 关键字

MyBatis 结果集映射 ⭐

  • 类型别名(typeAliases)
  • 结果集映射到 Bean
  • 结果集映射到 Map
  • 高级结果集映射(resultMap,当结果集里面包含对象时使用)
  • 执行结果集的有参构造

MyBatisPlus 的配置文件
简单介绍了下 MyBatisPlus 的配置

  • 别名包扫描路径
  • 自动驼峰命名规则
  • 开启缓存(开启 Mybatis 二级缓存)
  • DB 策略配置(默认主键生成策略、表名前缀)

MyBatisPlus 常用的增删改查
如题,简单介绍了下 MyBatisPlus 怎么用

MyBatisPlus 常用的插件工具
介绍了 MyBatis 如何定义插件,MyBatis 可以在 已映射语句 执行过程中的某一点进行拦截调用

  • 性能分析插件 ⭐
  • SQL 自动填充(自动填充那些没有传值的字段,例如时间) ⭐
  • 逻辑删除插件 ⭐
  • 通用枚举(就是对一些约定的参数进行映射,例如 flag 字段在数据库中是通过 int 类型存储的,0 代表 xx、1 代表 xxx)
  • 代码生成器(有更方便的插件了) ⛔

MyBatisPlus 的 ORM 操作
搭配 Java 提供的 JPA 规范一起食用:
ORM 的概念学习~
Java JPA 规范

  • 什么是 ORM(”对象-关系映射” 即 Object/Relational Mapping)
  • MyBatis 与 ORM 的关系
  • JPA、Hibernate、Spring Data JPA 的关系(网上常说的 JPA 其实是指 Spring Data JPA 这个框架)
  • JPA 中的元数据注释 ⭐
  • 在 MyBatis Plus 中使用 JPA 注解

计算机基础

操作系统之内存
这篇主要是介绍一下内存在操作系统里面是怎么工作的

  • 虚拟内存的概念(操作系统会为每个进程分配独立的一套「虚拟地址」)
  • 内存分段 => 内存分页(多级分页) => 内存段页 (内存在操作系统中组织方式的演化)

Linux IO 基本概念学习(IO 多路复用) ⭐
在 Redis 和 NIO 都使用到了这个 IO 多路复用,所以它是原理部分重头戏
主要知识点:

  • select、poll、epoll 的异同(主要看 epoll 与前面两种方式实现的多路复用区别)
  • IO 多路复用真的是 “全” 异步吗?(主要理解 多路复用也是一种 “blocking IO” )

用户态与内核态是啥?
这个是理解下面零拷贝技术的知识铺垫
主要知识点:

  • CPU 指令集权限(核心)
  • 用户态与内核态的切换(主要是理解效率过低的问题)
  • 为什么需要内核缓存?

零拷贝技术是什么? ⭐
Kafka ,Netty,Nginx 都使用这个零拷贝技术,其实零拷贝就是想方设法地 优化减少或者去掉用户态和内核态之间以及内核态和内核态之间的数据拷贝
主要知识点:

  • DMA 技术(零拷贝的基础)
  • 传统的文件传输(主要是 4 次用户态与内核态的上下文切换,4 次数据拷贝)
  • sendfile 系统调用函数,零拷贝的核心(降低到 2 次上下文切换,和 2 次数据拷贝)
  • PageCache 的缺陷:大文件传输(使用异步IO 加直接 IO的方式避免装到 PageCache)

网络基础与网络安全

渣渣大学生三年的学习笔记:Java 基础知识整理_第1张图片

ARP 协议
地址解析协议,即 ARP(Address Resolution Protocol),是根据 IP 地址获取物理地址的一个 TCP/IP 协议。

  • 免费 ARP(指主机发送 ARP 请求查找自己的 IP 地址,目的是测试网络上是否存在重复的 IP)
  • 代理 ARP(跨网段需要使用路由器的代理 ARP,但是可能会存在代理 ARP 欺骗的问题) ⭐

链路层协议 ⛔
链路层在各层协议中要直接打交道的就是 IP、ARP 和 RARP 3个协议

DNS 学习 ⛔

  • 常见的域名前缀
  • DNS 的解析类型

HTTP 协议学习

  • 为什么基于 TCP 的 HTTP 是无状态呢?(这个无状态是指每一次请求之间是没有联系的)
  • HTTP 1.1 的长连接(这个 keep-alive 指的是在一定时间内复用同一个 TCP 连接,而不是 HTTP 长连接) ⭐
  • 长轮询和短轮询(短轮询:每次都响应,长轮询:如果有变化才会立即返回结果否则直接让它超时)
  • HTTP 各版本区别 ⭐
  • HTTP 报文
  • 分片传输

TCP 的连接管理

  • TCP 的连接建立(三次握手的过程)
  • 为什么是三次握手而不是两次握手? ⭐
  • TCP 的连接释放(四次挥手的过程)
  • TCP 维持连接(长连接与短连接、网络层面连接的保活:KeepAlive、应用层连接的保活:应用层心跳;这里还解释了为什么 WebSocket 需要应用层心跳连接)

TCP 的可靠传输 ⛔
详细的介绍了下 TCP

  • 数据编号与确认
  • 滑动窗口
  • 快速重传
  • 选择确认
  • 超时重传时间

TCP 的报文基本结构

  • TCP 的主要特点 ⭐
  • TCP 报文结构(固定报文字段、6 个标志位、可选部分)

TCP 的流量控制

  • 为什么需要流量控制?(如果应用程序读取数据比较慢,而发送方发送数据很快、很多,则很容易使该连接的接收缓存溢出)
  • 流量控制的原理(TCP 采用接收方控制发送方发送窗口大小的方法来实现在TCP连接上的流量控制)
  • 拥塞控制
  • TCP 最大连接数(一个网卡对应一个IP地址、一个 IP 地址对应 65535 个端口、一个 socket(addr, port) 可以接受多个 socket 连接(accept)、一个端口只能被一个 socket 监听(listen))

WebSocket 学习
WebSocket 使用案例:WebSocket 心跳机制和重连实现

  • WebSocket 是怎么建立连接的?(协议升级的过程)
  • Websocket 事件
  • WebSocket 控制帧
  • 子协议的使用

跨源资源共享 CORS
CORS 全称是 Cross-Origin Resource Sharing,直译过来就是跨域资源共享。这个是经常遇到的坑,学习一下方便排查错误

  • 同源策略详情
  • JSONP 和 CORS(使用 JSONP 可以跨过同源策略)

数据结构与算法

数据结构

数据结构 Heap 堆
堆这个数据结构主要是对完全二叉树的拓展,这篇主要是为堆排序做铺垫,堆是一种特殊的完全树,它每个结点都有一个值,堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。就类似一堆东西一样,按照由大到小(或由小到大)“堆” 起来。
主要知识点:

  • 数组的堆化 shiftDown(时间复杂度: O ( l o g n ) O(logn) O(logn)
  • 插入、删除操作(时间复杂度: O ( l o g n ) O(logn) O(logn)

排序算法

简单排序算法
简单排序和时间复杂度

  • Comparable 接口(定义了自然排序的排序方式)
  • 常用排序时间复杂度
  • 排序的稳定性的意义(如果一组数据只需一次排序,则稳定性没有意义,如果一组数据需要使用多次排序,稳定性则有意义)
  • 简单排序(重点看插入排序)

高级排序算法 归并排序
利用归并的思想实现的排序方法,分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案 “修补” 在一起,即分而治之。归并排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

  • 计算递归算法的时间复杂度

高级排序算法 快速排序
快速排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),它的空间复杂度是 O ( l o g n ) O(logn) O(logn) 最坏情况是 O ( n 2 ) O(n^2) O(n2)

  • 基于荷兰国旗问题的快排 ⭐

高级排序算法 堆排序
堆排序其实就是利用堆的性质进行排序(算是第一个利用),堆排序时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn) 且堆排序对原始记录的排序状态并不敏感

高级排序算法 桶排序
桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里。每个桶再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后依次把各个桶中的记录列出来记得到有序序列。

高级排序算法 基数排序
算法的时间复杂度是 O ( n ) O(n) O(n),但是因为基数排序不是基于比较的排序,所以适用面比较低一点,基数排序也算一种桶排序。

Bitmap 位图排序
使用 bitmap 主要是可以减少存储空间的使用,用一个 bit 来存储一个元素的状态(就是利用了二进制位数,例如第二位为 1 ,那就表示存在 2 这个数)。例如当我们需要在一亿个数中判断某个数是否存在时,我们不需要将这一亿个数同时放入内存。这个排序是一种特殊的排序,使用起来有诸多限制

高级排序算法 希尔排序 ⛔
希尔排序是插入排序的一种改进版本,避免了插入排序那种每次只能将数据移动一位,采用 跳跃分割的策略:将相距某个 “增量” 的记录组成一个子序列,令整体相对有序,然后依次缩减增量再进行排序(希尔排序之所以那么快,是因为一次可以排多个,使之基本有序)

  • 希尔排序(Shell Sort)的最好的复杂度大概能到 O ( n 1.2 ) O(n^{1.2}) O(n1.2) O ( n 1.3 ) O(n^{1.3}) O(n1.3) 的样子,主要受选择的增量序列影响,但是最好也达不到 O ( n l o g n ) O(nlogn) O(nlogn),因此它一般情况是干不过快排的

查找算法

设计模式

设计模式基本概念
主要介绍了一些设计模式的概念

  • 各种模式的分类
  • 高内聚与松耦合(高内聚:内部完整,松耦合:条理清晰,不至于牵一发而动全身)
  • 单一职责原则:就一个类而言,应该仅有一个引起它变化的原因(功能要单一)
  • 开放封闭原则:对于扩展是开放的、对于更改是封闭的
  • 依赖倒转原则:高层模块不应该依赖底层模块,两个都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。(换句话说就是面向接口编程)
  • 里氏代换原则:子类型必须能够替换掉它们的父类型
  • 迪米特法制(最少知识原则)
  • 合成\聚合 复用原则(聚合优于继承)
  • 如何查看 UML 类图
  • 创建型模式的作用:把类型的 “定义过程” 和 “实例化过程” 分离开
  • 结构型模式的作用:描述如何将类或者对象结合在一起形成更大的结构
  • 行为型模式的作用:对在不同的对象之间划分责任和算法的抽象化

什么是好的软件架构 ⭐
评价架构设计的好坏就是评价它应对改动有多么轻松

  • 解耦帮了什么忙?(最小化在编写代码前需要了解的信息)
  • 抽象的架构可能会造成性能和速度上的损失

游戏开发中的 MVC 模式 ⭐
MVC 这个模式是由 策略模式、观察者模式 和 组合模式 这三个基本的设计模式组成的

  • 数据层中的观察者模式(监听者模式实现了各参与者的解耦,通过消息来实现相互协作,其实这里是发布订阅模式)
  • 逻辑层:策略模式(例如不同的请求就执行不同的控制器)
  • 视图层:组合模式(一个页面整体框架是一样的,但是里面具体的各个内容可能不太一样)
  • 前后端 MVC 区别(后端 MVC 中的 view 是前端 MVC 的全部)

创建型模式

单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。

创建型模式-单例模式
这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象,饿汉式是类加载时就初始化,一般懒汉式才需要考虑线程安全的问题。(注意,它和静态工具类还是有区别的,工具类是无需实例化的)

  • 饿汉式(常用,创建时无需加锁,但是类加载时就初始化,浪费内存) ⭐
  • 枚举方式(推荐,创建枚举默认就是线程安全的,实际上和上面是一样的,类加载时就初始化,浪费内存)
  • 懒汉式(使用同步锁 synchronized 防止多线程同时进入造成 instance 被多次实例化)
  • 双重检验锁的隐患(可能会出现指令重排的问题,所以单例对象要加 volatile 关键字修饰来避免指令重排) ⭐
  • 静态内部类方式(利用静态内部类的特性,只有在其被第一次引用的时候才会被加载,所以可以保证其线程安全性)

创建型模式-原型模式
这个原型模式在 Java 主要就是考察 浅表复制与深层复制,但是在 JavaScript 中却很不一般(Self 语言)
主要知识点:

  • 浅表复制与深层复制(主要就是序列化的方式来实现复制) ⭐
  • 原型语言范式(JavaScript 的原理 “原型对象”)

创建型模式-工厂模式
在工厂模式中,我们在 创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。JDK 中也是挺常用的,例如线程池的 Executors 工具类就是使用的工厂模式。

  • 简单工厂(静态工厂模式,但是有违背开放封闭原则的缺点)
  • 工厂方法模式(主要就是避免像简单工厂那样每次都需要修改工厂方法,工厂方法模式只需实现一个工厂类就可以创建新的实例了,这样就满足了开放封闭原则)
  • 抽象工厂模式(提供一个创建 一系列 相关或相互依赖对象的接口,例如创建一整套不同风格的家具)

创建型模式-建造者模式
建造模式适用于一个具有较多零件的复杂产品的创建过程,由于需求会经常变更,组成这个复杂产品的各个零件经常变化,但是它们的 组合方式却相对稳定

行为型模式

模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

行为型模式-命令模式
命令模式将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化; 对请求排队或记录请求日志,以及支持可撤销的操作。

行为型模式-拦截器模式
拦截过滤器模式当我们想对应用程序的请求或响应进行一些预处理/后处理时,将使用拦截过滤器设计模式。(注意与过滤器模式的区别:过滤模式允许开发人员使用各种标准过滤 一组对象

行为型模式-模板方法模式
模板方法模式就是定义一个算法的骨架,将算法分解为一系列步骤, 然后将这些步骤改写为方法, 最后在 “模板方法” 中依次调用这些方法。

行为型模式-状态模式
用来去除代码里面大量的 if else,状态模式通过把各种状态逻辑转移分布到 state 的子类之间来减少相互之间的依赖(就像 Unity 的 Animator Controllers 那样的状态机的概念)

行为型模式-策略模式
该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。

  • 枚举实现策略模式 ⭐

行为型模式-职责链模式
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止(就像异常处理那样,层层上抛,直到有个能处理它的为止)。

行为型模式-观察者模式和发布订阅模式
主要就是观察者模式和发布订阅模式的区别:发布订阅模式是最常用的一种观察者模式的实现,并且从解耦和重用角度来看,更优于典型的观察者模式(观察者无需直接耦合主题,而是委托事件中心这个第三方)

行为型模式-解释器模式
给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。(MyBatis 的那个就是解释器模式)

行为型模式-访问者模式
适用于 数据元素相对稳定 的场景,它能将算法与其所作用的对象隔离开来(例如男人女人执行不同的策略)

行为型模式-迭代器模式
大部分语言使用的 foreach 实际就是使用的迭代器,在日常开发中,几乎不会自己写迭代器。除非需要定制一个自己实现的数据结构对应的迭代器,否则,开源框架提供的 API 完全够用。

结构型模式

适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。

☕ Java 代理模式
这篇博客需要先了解前面 Java 反射,主要考察的是动态代理,因为代理模式是后面学习 AOP、IoC 的基础

  • JDK 的动态代理 ⭐
  • CGLIB 动态代理机制

结构型模式-享元模式
它摒弃了在每个对象中保存所有数据的方式,通过共享多个对象所共有的相同状态,让你能在有限的内存容量中载入更多对象。其实就是 对象池 的概念

  • 享元 Flyweight(传递给享元方法的状态 被称为 “外在状态”)
  • 不需要共享的享元子类

结构模式-外观模式
给屎山擦屁股的专用设计模式,外观模式就是用来隐藏子系统的复杂性,并向客户端提供一个可访问的接口

结构模式-桥接模式
将抽象与实现分离,使它们可以独立变化。它是 用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。(例如手机品牌和手机软件独立变化)

结构模式-类型对象模式
这个是补充的设计模式,对于一些需要大量不同 “类型” 对象的场景可以使用(其实就是上面 桥接模式的一种具体的应用

结构模式-组合模式
将对象组合成树形结构表示:“部分-整体” 的层次结构(组合模式使得用户对单个对象和组合对象的使用具有一致性),例如 Unity 的各个组件和对象就是这种思路

☕ 结构模式-装饰器模式
装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。例如 Java8 中 Stream 的惰性计算就是这个原理。

结构模式-过滤器模式
这种模式允许开发人员使用不同的标准来过滤 一组对象(数组、List),通过逻辑运算以解耦的方式把它们连接起来。注意,它和拦截器模式的区别(过滤模式允许开发人员使用各种标准过滤 一组对象,而当有人需要对应用程序的请求或反应进行一些预先准备/后处理时,就使用拦截模式)

结构模式-适配器模式
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁,不过一般实际应用中,这个适配器用起来更像模板方法模式(例如 SpringSecurity 的那个 WebSecurityConfigurerAdapter)

Spring 大礼包

Spring

Spring 由哪些模块组成?
主要介绍了下 Spring 由哪些模块构成

  • 核心容器(主要就是 Bean 工厂,Spring 应用程序上下文,Spring-Core 模块,EL 表达式的支持)
  • AOP 和设备支持
  • 数据访问与集成
  • Web 相关
  • 消息(Messaging,就是消息队列的支持)
  • Test(使用 JUnit)

Spring基础知识:IoC DI 补充:IoC 容器的简单实现之配置文件的读取

  • 什么是 IoC ?(实际上 IoC 就是设计模式中的依赖倒转原则)
  • IoC 和 DI 的关系(Dependency Injection 即 “依赖注入”,其是 Spring 实现控制反转的方式)
  • @Autowired@Resource 的区别(前者 byType 后者 byName 再 byType)

Spring基础知识 AOP
这篇其实没啥好说的,搭配下面的一起食用:

  • Spring EL 表达式
  • SpringBoot 整合 AOP
  • SpringBoot 使用 AOP 做请求限流

Spring 循环依赖问题(三级缓存)
补充一点,使用构造函数注入和 @Autowired 有点小区别,前者出现循环依赖有更好看的报错显示(笑)

  • 循环依赖发生的时机(填充属性 / 方法的过程中,如果是使用构造方法注入就是实例化的时候)
  • Spring 如何解决的(三级缓存)
  • 两级不能解决么?(这样就无法在初始化完对象后执行自定义的 init 方法了)

Spring Bean 生命周期常见的拓展点
这篇笔记比较复杂,主要配合着第一张图进行理解

  • 四个阶段干了什么事(实例化、属性赋值、初始化、销毁)
  • 影响多个 Bean 的接口(实现了这些接口的 Bean 会切入到多个 Bean 的生命周期中,自动注入以及 AOP 的实现都和他们有关)
  • 只调用一次的接口:Aware 类型接口(Aware 类型的接口的作用就是让我们能够拿到 Spring 容器中的一些资源)

Spring Bean 的杂项知识

  • Bean 的作用域有哪些?(主要 singleton 单例、prototype 原型,注意要自己实现单例内部的线程安全)
  • @Component@Bean 的区别(第三方库中的组件一般用 @Bean,这样更灵活)

Spring 中 BeanFactory 与 FactoryBean 的区别 ⛔

  • BeanFactory 是什么?(用于管理 Bean 的一个工厂)
  • FactoryBean 是什么?(它是一个生产或修饰对象生成的工厂 Bean,例如用来 创建 AOP 的代理对象)
  • 它们两个的区别?(BeanFactory 是顶层接口只是用来创建 Bean,很多拓展功能做不了,FactoryBean 虽然也是一个由 BeanFactory 创建的 Bean 但是可以委托它给 Bean 的实现加上了一个简单工厂模式和装饰模式)

Spring 的 ApplicationContext 应用上下文学习 ⛔

  • Spring ApplicationContext 是什么?(Bean Factory 的一个比较好的实现类)

Spring 中用到的设计模式

  • 控制反转(IoC)和依赖注入(DI),就是设计模式中的依赖倒转原则
  • 工厂设计模式(BeanFactory 其实更像工厂方法,它抽象出了创建对象的工厂接口,例如 XmlBeanFactory、ApplicationContext 都是它的实现类)
  • 单例设计模式(Bean 默认都是单例,Spring 通过 ConcurrentHashMap 实现单例注册表的特殊方式实现单例模式)
  • 代理模式在 AOP 中的应用(其实就是在创建 Bean 之前先执行了 AOP 查看哪些对象需要被代理,然后创建一个代理对象放在 Bean 工厂里面代替被代理对象)
  • 模板方法(定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,例如 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类)
  • Spring 中的观察者模式(其实就是发布订阅模式,具体参考下面 Spring 内的事件框架)

Spring 中的事件机制

  • JDK中对事件监听机制的支持(了解下 JDK 自带的接口)
  • Spring 容器对事件监听机制的支持(Spring 对 JDK 提供的监听接口进行了简化)
  • 提供的 5 种标准的事件

Spring 事务的使用~
搭配 Spring 事务属性详解~、Spring 事务的核心概念~ 一起食用

  • 事务传播行为(有点像 MySQL 嵌套事务 的概念)
  • 事务隔离级别(就是自动切换当前事务的隔离级别,它默认使用的隔离级别是根据 JDBC 对应的数据库决定的)
  • 事务超时属性(指一个事务所允许执行的最长时间)
  • 事务只读属性(设置事务只读,为了避免不可重复读、幻读的问题,查询也需要事务)
  • 回滚规则(定义事务失败时执行的异常)

SpringMVC

SpringMVC 基本执行流程
其实没啥好说,就是一些请求响应之类配置,配合下面的一起看:

  • SpringMVC 接收参数
  • SpringMVC 响应数据
  • SpringMVC 拦截器与过滤器(主要是搞清过滤器和拦截器的区别)

SpringBoot

SpringBoot 自动装配原理
这篇说是原理,其实就是介绍了一下如何自己编写一个 starter,它的核心原理就是按照 META-INF/spring.factories 文件自动导入写好的 Bean

  • 搭配:SpringBoot 配置文件相关 (编写一个配置类)

补充一些 SpringBoot 提供的工具

SpringBoot 定时任务
Spring Scheduled 是一个 Spring 自带的定时器工具,不需要手写线程池相关代码,只需要两个注解即可。

SpringBoot 数据校验
每次在 Request 请求携带过来的参数校验很麻烦,这种情况就可以使用 Spring validation 校验数据

SpringBoot 的 “开机启动”
很多时候,我们都需要在 SpringBoot 项目启动后初始化化一些自己的数据,这时可以使用这两个注解做 “开机启动”

在 SpringBoot 中使用 Redis Cache 主要看下面这几篇

  • SpringBoot 使用 Redis 实现 Session 共享
  • SpringBoot 使用 AOP 做请求限流
  • SpringBoot Cache 的使用 (介绍了下 Spring Cache 这个接口)

Spring Security

Spring Security 虽然强大,但是也是真的难用,这里暂时先放这里,等以后有时候了再来整理这块

SpringSecurity 使用自带的 formLogin (快速使用表单登陆)
SpringSecurity 配置项

SpringSecurity 原理篇 快速上手教程 (理解各个组件的作用)
SpringSecurity 原理篇 认证流程源码解析
SpringSecurity 原理篇 鉴权流程源码解析

SpringSecurity 整合 JWT 快速使用
SpringSecurity 使用 RSA 非对称加密 (JWT 如何使用 RSA)
SpringSecurity 工具类 BCryptPasswordEncoder 是如何加密解密的

SpringSecurity RBAC设计(入门)
SpringSecurity 认证的编写流程
SpringSecurity 编写一个简单鉴权Demo
SpringSecurity 访问控制的方式

SpringSecurity授权服务器、资源服务器
SpringSecurity 单点登陆 SSO(只是介绍了概念)
SpringSecurity OAuth2 的各种概念 (如何选择 OAuth 的各种模式)
OAuth2.0 数据库字段说明
Spring Cloud Security OAuth2 学习(如何配置授权服务器)
SpringSecurity OAuth GitHub 登陆案例 (快速上手资源服务器如何对接外部的认证服务器)
OAuth2.0 分布式系统环境搭建(快速上手认证服务器和资源服务器的交互)
SpringSecurity OAuth2 自定义用户密码登陆返回 Token

补充 Shiro

安全框架 Shiro 授权
安全框架 Shiro 身份认证

分布式

理论和算法

分布式自增 ID 算法 Snowflake(雪花算法)
为了防止 ID冲突可以使用 36位的 UUID,但是 UUID有一些缺点,首先他相对比较长,另外 UUID一般是无序的。所以这时可以采用雪花算法

你可能感兴趣的:(java,spring,设计模式)