From c3e5aeb70296c677a33c007580a083c9d794c805 Mon Sep 17 00:00:00 2001 From: CompetitiveLin Date: Mon, 2 Dec 2024 18:46:38 +0800 Subject: [PATCH] 20241202 --- _posts/2022-06-21-java.md | 43 +++++++++++++++++++---------- _posts/2022-06-22-mysql.md | 25 +++++++++++++++-- _posts/2023-09-07-note-from-work.md | 7 +++++ 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/_posts/2022-06-21-java.md b/_posts/2022-06-21-java.md index 70ad14503..fa1a5594b 100644 --- a/_posts/2022-06-21-java.md +++ b/_posts/2022-06-21-java.md @@ -15,12 +15,13 @@ pin: true 装箱:`Integer i = Integer.valueOf(10)`, 拆箱:`int n = i.intValue()` +反射:指动态获取的信息以及动态调用对象的方法的功能。在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性 # 内存结构 ![](https://img-blog.csdnimg.cn/cb59671dff1f4588b5d845f60874013b.png) -运行时数据区域包含线程私有的程序计数器、虚拟机栈、本地方法栈,线程共享的堆(包含字符串常量池)和非运行时数据区的元空间(包含类常量池和运行时常量池)、直接内存。 +运行时数据区域包含线程私有的程序计数器、虚拟机栈、本地方法栈,线程共享的堆(包含字符串常量池)。直接内存(堆外内存)包含元空间(包含类常量池和运行时常量池)。 - 程序计数器:与操作系统中的程序计数器类似,为了线程切换后能恢复到正确的执行位置,是唯一一个不会出现 `OutOfMemoryError` 的内存区域。 - 虚拟机栈:以帧为单位,帧由局部变量表、操作数栈、动态链接、方法返回地址组成。每一次方法调用都会有一个对应的栈帧被压入栈中,每一个方法调用结束后,都会有一个栈帧被弹出。 - 局部变量表:主要存放了编译期可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、**对象引用**(reference 类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置) @@ -33,12 +34,27 @@ pin: true - 类常量池:每个java文件被编译成class文件后会有一项常量池,用于存放编译器生成的**字面量**和**符号引用**。在**编译**阶段,存放的是常量的**符号引用**。 - 运行时常量池:是在**类加载完成后**,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析阶段,将符号引用替换成直接引用,与字符串常量池中的引用值保持一致。 + +## 方法区 + +### 永久代和元空间的区别 + +在 hotpot 虚拟机中,JDK7以前的方法区是用永久代实现的;在JDK8后,方法区用元空间实现的。最大的区别:元空间位于本地内存上;而永久代位于虚拟机内存中,与堆是连续的一块内存。 + +### 垃圾回收 +只有 Full GC 时执行垃圾回收,主要回收两部分内容: +1. 常量池中废弃的常量 +2. 不再使用的类型,类需要同时满足下面 3 个条件才能被卸载: + 1. 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。 + 2. 加载该类的 ClassLoader 已经被回收。 + 3. 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。 + [class常量池、字符串常量池和运行时常量池的区别](https://blog.csdn.net/xiaojin21cen/article/details/105300521) # [内存模型(JMM)](https://zhuanlan.zhihu.com/p/258393139) -JMM 旨在提供一个统一的可参考的规范,屏蔽平台内存访问差异性。这个规范为读写共享变量时如何与内存交互提供了规则和保证。并发编程中,程序会因为 CPU 多级缓存或指令重排序等出现问题,因此需要一些规范要保证并发编程的可靠性。 +JMM 旨在提供一个统一的可参考的规范,屏蔽平台内存访问差异性。这个规范为多线程读写共享变量时如何与内存交互提供了规则和保证。并发编程中,程序会因为 CPU 多级缓存或指令重排序等出现问题,因此需要一些规范要保证并发编程的可靠性。 关键概念包括: - 主内存:表示所有线程都可以访问的共享内存。线程不能直接读写主内存中的变量。 @@ -124,12 +140,6 @@ Tomcat中的类加载器: Java的SPI:SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。当服务的提供者提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 - -1.6 -> 1.7 -> 1.8: -- 1.6 -> 1.7: 字符串常量池从方法区(永久代)中移到堆中。原因: GC 回收效率太低,只有在整堆收集 (Full GC)的时候才会被执行 GC。Java 程序中通常会有大量的被创建的字符串等待回收。 -- 1.7 -> 1.8: 将运行时数据区方法区(永久代)移动到直接内存中,字符串常量池仍然在堆中。 - - ## 对象的创建过程 1. 类加载检查 2. 分配内存:指针碰撞或空闲列表 @@ -195,9 +205,9 @@ JVM触发GC时,首先会让所有的用户线程到达安全点SafePoint时阻 ## [垃圾收集器](https://cloud.tencent.com/developer/article/1592943) 1. Serial 收集器,单线程、复制算法的新生代收集器 2. ParNew 收集器,多线程、复制算法的新生代收集器,老年代采用Serial Old收集器 -3. Parallel Scavenge 收集器,多线程、复制算法的新生代收集器,高吞吐量。 +3. Parallel Scavenge 收集器,多线程、**复制算法**的新生代收集器,高吞吐量。 4. Serial Old 收集器,单线程、标记-整理算法的老年代收集器。 -5. Parallel Old 收集器,多线程、标记-整理算法的老年代收集器。 +5. Parallel Old 收集器,多线程、**标记-整理算法**的老年代收集器。 6. CMS(Concurrent Mark Sweep) 收集器,标记-清除算法,以获取最短回收停顿时间为目标的收集器。JDK14正式移除。 7. G1(Garbage-First) 收集器,标记-整理 + 复制算法,内存碎片的产生率大大降低。JDK9-JDK17的默认垃圾收集器。 @@ -205,9 +215,9 @@ JVM触发GC时,首先会让所有的用户线程到达安全点SafePoint时阻 _G1收集器内存模型_ 垃圾收集器发展历程: -- JDK8 默认 Parallel Scavenge + Parallel Old +- JDK8 默认 Parallel Scavenge(标记-复制) + Parallel Old(标记整理) - JDK9 默认 G1 -- JDK11 提出ZGC +- JDK11 提出 ZGC - JDK14 CMS 被移除 @@ -379,7 +389,7 @@ Java 中的线程分为两种: - Collections.synchronizedList() 读少写多的情况 [HashMap 知识点](https://zhuanlan.zhihu.com/p/151027796) -- HashMap: 乱序,数组+链表+红黑树,链表长度大于8转红黑树,红黑树节点个数小于6转链表。 +- HashMap(JDK8): 乱序,数组+链表+红黑树+尾插法,链表长度大于8并且数组长度大于64时转红黑树,红黑树节点个数小于6转链表。JDK7时用数组+链表+头插法(可能造成循环链表)实现。 - LinkedHashMap: 按插入顺序排序 - TreeMap: 按字典序排序,因为是按字典序排序的,所以键肯定不能为null,值可以为null - IdentityHashMap:利用哈希表实现Map接口,不同的是,其比较键(或值)时,使用引用相等性代替对象相等性。 @@ -389,13 +399,16 @@ Java 中的线程分为两种: 为什么计算哈希值采用低十六位和高十六位异或操作: - 计算数组下标是与操作,只有低 n 位进行与操作,高位不参与任何操作 -> 为了增大散列程度减小哈希碰撞,因此将高十六位参与进哈希值的计算。 +计算数组下标是与操作,只有低 n 位进行与操作,高位不参与任何操作 -> 为了增大散列程度减小哈希碰撞,因此将高十六位参与进哈希值的计算。 put() 的流程: 1. hashcode的高十六位和低十六位进行异或运算 2. (n - 1) & hash 计算数组下标,当 n 为二次幂时,等价于取余操作((n - 1)& hash = hash % n)。 3. 判断当前下标是否有元素,若有元素,使用尾插法。再根据链表长度判断是否需要转换成红黑树。 +第一次扩容:执行第一次 put() 操作时,如果数组为空便会执行第一次扩容操作,初始化数组容量为默认大小。 + + 扩容的过程: 1. 将数组扩容成原数组的两倍 2. 如果没有哈希冲突的节点,使用 `e.hash&(newCap - 1)` 计算新的桶位置 @@ -423,7 +436,7 @@ NULL key AND NULL value: ConcurrentHashMap JDK7 vs JDK8 - JDK7: 数组 + 链表。先定位 Segment,再定位桶。底层结构是继承了ReentrantLock的Segment数组。可以看成是由线程安全的HashMap组成的一个map数组,数组的长度决定了支持的最大的并发量。 -- JDK8: 数组 + 链表 + 红黑树。可以直接定位到桶。链表中的元素超过8后,将链表结构转换成红黑树。通过对Node数组以CAS方式实现扩容和对Node数组的每个元素的synchronized保证ConcurrentHashMap整体的线程安全。 +- JDK8: 数组 + 链表 + 红黑树。可以直接定位到桶。链表中的元素超过8并且数组长度大于64后,将链表结构转换成红黑树。通过对Node数组以CAS方式实现扩容和对Node数组的每个元素的synchronized保证ConcurrentHashMap整体的线程安全。 ![](https://raw.githubusercontent.com/CompetitiveLin/ImageHostingService/picgo/imgs/202305151605481.png) diff --git a/_posts/2022-06-22-mysql.md b/_posts/2022-06-22-mysql.md index e6ca4b804..8c489466d 100644 --- a/_posts/2022-06-22-mysql.md +++ b/_posts/2022-06-22-mysql.md @@ -118,7 +118,7 @@ varchar:变长 1. 不满足最左匹配(覆盖索引,索引下推,索引跳跃扫描) 2. 尽可能明确查询列,而不是select *,即使不满足最左匹配(可以用于性能优化) -3. 错误的like使用(当模糊匹配的占位符位于条件的首部,并且要看数据库中的字段) +3. like关键字的左模糊和左右模糊(如果覆盖索引便不失效) 4. 错误的or使用(切记两个条件都要添加索引,否则会导致索引失效,or两边同时使用 < 和 >,也会失效) 5. 错误的 <> 和 != 使用(查询结果集占比较大时索引会失效) 6. is not null(is null 走索引) @@ -382,10 +382,31 @@ Binlog 的持久化: - 共享锁:读锁,其他事务可以读,但不能写,`select lock in share mode` - 排他锁:写锁,其他事务不能读,也不能写,`select for update` + +# For update 加什么锁 + +## RC 隔离级别 + +1. 唯一索引 + 有值:记录锁 +2. 主键 + 有值:记录锁 +3. 普通索引 + 有值:记录锁 +4. 无索引 + 有值:记录锁 + +## RR 隔离级别 +1. 主键查询 + 有值:记录锁 +2. 主键查询 + 空值:间隙锁 +3. 唯一索引 + 有值:记录锁 +4. 唯一索引 + 空值:间隙锁 +5. 普通索引 + 有值:间隙锁 +6. 普通索引 + 空值:间隙锁 +7. 索引 + 范围查询:间隙锁 + +只要通过查询条件查到的数据不唯一,就加间隙锁。 + ## mysql 数据实时同步到Es 常见的数据同步方案主要有以下三种: 1. 同步调用。在实现增删改的同时,通过调用ES所在服务提供的接口。 -2. 异步调用。增删改服务和搜索服务分别通过MQ进行发送和监听消息,有效降低业务的耦合度,但较为依赖MQ的性能; +2. 异步调用。增删改服务和搜索服务分别通过MQ进行发送和监听消息,有效降低业务的耦合度,但较为依赖MQ的性能。 3. binlog监听。给MySQL开启binlog功能,搜索服务基于canal监听binlog变化,但开启binlog会增加数据库负担、同时实现复杂度较高。 但也有异步调用和binlog监听结合在一起的[例子](https://github.com/Scoefield/syncMySqlToES),用canal作slave节点。 diff --git a/_posts/2023-09-07-note-from-work.md b/_posts/2023-09-07-note-from-work.md index 75781372b..880b22f09 100644 --- a/_posts/2023-09-07-note-from-work.md +++ b/_posts/2023-09-07-note-from-work.md @@ -27,6 +27,13 @@ pin: false 3. 漏桶:记录上次请求时间戳、当前剩余水量和容量,每次请求计算当前剩余水量减去时间差乘以每秒处理数,判断是否小于容量,是则放行并增加水量,不是则限流 4. 令牌桶:记录上次请求时间戳、当前令牌桶数量和容量,每次请求计算当前令牌数量与时间差乘以每秒放入令牌数的和,如果当前令牌数大于零,则令牌数减一并放行,否则限流 +## Cookie 和 Session 的区别 +1. 存储位置:Cookie 存储在客户端,Session 存储在服务端 +2. 存取方式:Cookie 只能保存 ASCII,Session 可以存任意数据类型,比如 UserId 等 +3. 有效期:Cookie 可以长时间保持,Session 在客户端关闭的时候会失效 +4. 存储大小:单个 Cookie 大小不超过 4KB,Session 则没有限制 + + ## 数据结构 ### 红黑树特性