1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00

[docs update]typo

This commit is contained in:
Guide 2023-03-04 20:00:03 +08:00
parent cafb410791
commit 78fee25ee8
3 changed files with 12 additions and 4 deletions

View File

@ -38,7 +38,7 @@ icon: "lock"
### 如何基于 Redis 实现一个最简易的分布式锁? ### 如何基于 Redis 实现一个最简易的分布式锁?
不论是实现锁还是分布式锁,核心都在于“互斥”。 不论是本地锁还是分布式锁,核心都在于“互斥”。
在 Redis 中, `SETNX` 命令是可以帮助我们实现互斥。`SETNX`**SET** if **N**ot e**X**ists (对应 Java 中的 `setIfAbsent` 方法),如果 key 不存在的话,才会设置 key 的值。如果 key 已经存在, `SETNX` 啥也不做。 在 Redis 中, `SETNX` 命令是可以帮助我们实现互斥。`SETNX`**SET** if **N**ot e**X**ists (对应 Java 中的 `setIfAbsent` 方法),如果 key 不存在的话,才会设置 key 的值。如果 key 已经存在, `SETNX` 啥也不做。
@ -56,7 +56,7 @@ icon: "lock"
(integer) 1 (integer) 1
``` ```
为了误删到其他的锁,这里我们建议使用 Lua 脚本通过 key 对应的 value唯一值来判断。 为了防止误删到其他的锁,这里我们建议使用 Lua 脚本通过 key 对应的 value唯一值来判断。
选用 Lua 脚本是为了保证解锁操作的原子性。因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,从而保证了锁释放操作的原子性。 选用 Lua 脚本是为了保证解锁操作的原子性。因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,从而保证了锁释放操作的原子性。

View File

@ -58,7 +58,7 @@ class Class<T> {
} }
``` ```
简单来说,**类加载器的主要作用就是加载 Java 类的字节码( `.class` 文件)到 JVM 中(在内存中生成一个代表该类的 `Class` 对象)。** 字节码可以是 Java 源程序(`.java`文件)经过 javac 编译得来,也可以是通过工具动态生成或者通过网络下载得来。 简单来说,**类加载器的主要作用就是加载 Java 类的字节码( `.class` 文件)到 JVM 中(在内存中生成一个代表该类的 `Class` 对象)。** 字节码可以是 Java 源程序(`.java`文件)经过 `javac` 编译得来,也可以是通过工具动态生成或者通过网络下载得来。
其实除了加载类之外,类加载器还可以加载 Java 应用所需的资源如文本、图像、配置文件、视频等等文件资源。本文只讨论其核心功能:加载类。 其实除了加载类之外,类加载器还可以加载 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 9 引入了模块系统并且略微更改了上述的类加载器。扩展类加载器被改名为平台类加载器platform class loader。Java SE 中除了少数几个关键模块,比如说 `java.base` 是由启动类加载器加载之外,其他的模块均由平台类加载器所加载。
除了这三种类加载器之外,用户还可以加入自定义的类加载器来进行拓展,以满足自己的特殊需求。就比如说,我们可以对 Java 类的字节码( `.class` 文件)进行加密,加载时再利用自定义的类加载器对其解密。 除了这三种类加载器之外,用户还可以加入自定义的类加载器来进行拓展,以满足自己的特殊需求。就比如说,我们可以对 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. > 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) ![类加载器层次关系图](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/jvm/class-loader-parents-delegation-model.png)
注意⚠️:双亲委派模型并不是一种强制性的约束,只是 JDK 官方推荐的一种方式。如果我们因为某些特殊需求想要打破双亲委派模型,也是可以的,后文会介绍具体的方法。
其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,并不是说真的有一个 `MotherClassLoader` 和一个`FatherClassLoader` 。个人觉得翻译成单亲委派模型更好一些,不过,国内既然翻译成了双亲委派模型并流传了,按照这个来也没问题,不要被误解了就好。 其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,并不是说真的有一个 `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()` 方法。 **🐛 修正(参见:[issue871](https://github.com/Snailclimb/JavaGuide/issues/871) ** :自定义加载器的话,需要继承 `ClassLoader` 。如果我们不想打破双亲委派模型,就重写 `ClassLoader` 类中的 `findClass()` 方法即可,无法被父类加载器加载的类最终会通过这个方法被加载。但是,如果想打破双亲委派模型则需要重写 `loadClass()` 方法。
为什么是重写 `loadClass()` 方法打破双亲委派模型呢?双亲委派模型的执行流程已经解释了:
> 类加载器在进行类加载的时候,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成(调用父加载器 `loadClass()`方法来加载类)。
我们比较熟悉的 Tomcat 服务器为了能够优先加载 Web 应用目录下的类,然后再加载其他目录下的类,就自定义了类加载器 `WebAppClassLoader` 来打破双亲委托机制。这也是 Tomcat 下 Web 应用之间的类实现隔离的具体原理。 我们比较熟悉的 Tomcat 服务器为了能够优先加载 Web 应用目录下的类,然后再加载其他目录下的类,就自定义了类加载器 `WebAppClassLoader` 来打破双亲委托机制。这也是 Tomcat 下 Web 应用之间的类实现隔离的具体原理。
Tomcat 的类加载器的层次结构如下: Tomcat 的类加载器的层次结构如下: