From 78fee25ee8068b5b495421fedb78ba66e48df762 Mon Sep 17 00:00:00 2001 From: Guide Date: Sat, 4 Mar 2023 20:00:03 +0800 Subject: [PATCH] [docs update]typo --- .../mysql/images/{AID->C.drawio => AID-C.drawio} | 0 docs/distributed-system/distributed-lock.md | 4 ++-- docs/java/jvm/classloader.md | 12 ++++++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) rename docs/database/mysql/images/{AID->C.drawio => AID-C.drawio} (100%) diff --git a/docs/database/mysql/images/AID->C.drawio b/docs/database/mysql/images/AID-C.drawio similarity index 100% rename from docs/database/mysql/images/AID->C.drawio rename to docs/database/mysql/images/AID-C.drawio diff --git a/docs/distributed-system/distributed-lock.md b/docs/distributed-system/distributed-lock.md index 76fff6c6..edcf95ba 100644 --- a/docs/distributed-system/distributed-lock.md +++ b/docs/distributed-system/distributed-lock.md @@ -38,7 +38,7 @@ icon: "lock" ### 如何基于 Redis 实现一个最简易的分布式锁? -不论是实现锁还是分布式锁,核心都在于“互斥”。 +不论是本地锁还是分布式锁,核心都在于“互斥”。 在 Redis 中, `SETNX` 命令是可以帮助我们实现互斥。`SETNX` 即 **SET** if **N**ot e**X**ists (对应 Java 中的 `setIfAbsent` 方法),如果 key 不存在的话,才会设置 key 的值。如果 key 已经存在, `SETNX` 啥也不做。 @@ -56,7 +56,7 @@ icon: "lock" (integer) 1 ``` -为了误删到其他的锁,这里我们建议使用 Lua 脚本通过 key 对应的 value(唯一值)来判断。 +为了防止误删到其他的锁,这里我们建议使用 Lua 脚本通过 key 对应的 value(唯一值)来判断。 选用 Lua 脚本是为了保证解锁操作的原子性。因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,从而保证了锁释放操作的原子性。 diff --git a/docs/java/jvm/classloader.md b/docs/java/jvm/classloader.md index 1785be62..33f0d7e3 100644 --- a/docs/java/jvm/classloader.md +++ b/docs/java/jvm/classloader.md @@ -58,7 +58,7 @@ class Class { } ``` -简单来说,**类加载器的主要作用就是加载 Java 类的字节码( `.class` 文件)到 JVM 中(在内存中生成一个代表该类的 `Class` 对象)。** 字节码可以是 Java 源程序(`.java`文件)经过 javac 编译得来,也可以是通过工具动态生成或者通过网络下载得来。 +简单来说,**类加载器的主要作用就是加载 Java 类的字节码( `.class` 文件)到 JVM 中(在内存中生成一个代表该类的 `Class` 对象)。** 字节码可以是 Java 源程序(`.java`文件)经过 `javac` 编译得来,也可以是通过工具动态生成或者通过网络下载得来。 其实除了加载类之外,类加载器还可以加载 Java 应用所需的资源如文本、图像、配置文件、视频等等文件资源。本文只讨论其核心功能:加载类。 @@ -92,7 +92,7 @@ JVM 中内置了三个重要的 `ClassLoader`: > 🌈 拓展一下: > -> - **`rt.jar`** : rt 代表“RunTime”,``rt.jar`是Java基础类库,包含Java doc里面看到的所有的类的类文件。也就是说,我们常用内置库 java.xxx.* 都在里面,比如`java.util._`、`java.io._`、`java.nio._`、`java.lang._`、`java.sql._`、`java.math._`。 +> - **`rt.jar`** : rt 代表“RunTime”,`rt.jar`是Java基础类库,包含Java doc里面看到的所有的类的类文件。也就是说,我们常用内置库 `java.xxx.* `都在里面,比如`java.util.*`、`java.io.*`、`java.nio.*`、`java.lang.*`、`java.sql.*`、`java.math.*`。 > - Java 9 引入了模块系统,并且略微更改了上述的类加载器。扩展类加载器被改名为平台类加载器(platform class loader)。Java SE 中除了少数几个关键模块,比如说 `java.base` 是由启动类加载器加载之外,其他的模块均由平台类加载器所加载。 除了这三种类加载器之外,用户还可以加入自定义的类加载器来进行拓展,以满足自己的特殊需求。就比如说,我们可以对 Java 类的字节码( `.class` 文件)进行加密,加载时再利用自定义的类加载器对其解密。 @@ -178,6 +178,8 @@ public class PrintClassLoaderTree { ### 双亲委派模型介绍 +类加载器有很多种,当我们想要加载一个类的时候,具体是哪个类加载器加载呢?这就需要提到双亲委派模型了。 + 根据官网介绍: > The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader instance. @@ -197,6 +199,8 @@ public class PrintClassLoaderTree { ![类加载器层次关系图](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/jvm/class-loader-parents-delegation-model.png) +注意⚠️:双亲委派模型并不是一种强制性的约束,只是 JDK 官方推荐的一种方式。如果我们因为某些特殊需求想要打破双亲委派模型,也是可以的,后文会介绍具体的方法。 + 其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,并不是说真的有一个 `MotherClassLoader` 和一个`FatherClassLoader` 。个人觉得翻译成单亲委派模型更好一些,不过,国内既然翻译成了双亲委派模型并流传了,按照这个来也没问题,不要被误解了就好。 另外,类加载器之间的父子关系一般不是以继承的关系来实现的,而是通常使用组合关系来复用父加载器的代码。 @@ -286,6 +290,10 @@ protected Class loadClass(String name, boolean resolve) **🐛 修正(参见:[issue871](https://github.com/Snailclimb/JavaGuide/issues/871) )** :自定义加载器的话,需要继承 `ClassLoader` 。如果我们不想打破双亲委派模型,就重写 `ClassLoader` 类中的 `findClass()` 方法即可,无法被父类加载器加载的类最终会通过这个方法被加载。但是,如果想打破双亲委派模型则需要重写 `loadClass()` 方法。 +为什么是重写 `loadClass()` 方法打破双亲委派模型呢?双亲委派模型的执行流程已经解释了: + +> 类加载器在进行类加载的时候,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成(调用父加载器 `loadClass()`方法来加载类)。 + 我们比较熟悉的 Tomcat 服务器为了能够优先加载 Web 应用目录下的类,然后再加载其他目录下的类,就自定义了类加载器 `WebAppClassLoader` 来打破双亲委托机制。这也是 Tomcat 下 Web 应用之间的类实现隔离的具体原理。 Tomcat 的类加载器的层次结构如下: