From 5028e79934297fba93bb4388ce801285bfe978f1 Mon Sep 17 00:00:00 2001 From: wizardforcel <562826179@qq.com> Date: Tue, 26 Nov 2019 18:42:18 +0800 Subject: [PATCH] 2019-11-26 18:42:18 --- docs/31.md | 14 ++++++-------- docs/32.md | 31 ++++++++++++++----------------- docs/33.md | 2 +- docs/34.md | 22 +++++++++++----------- docs/35.md | 22 +++++++++++----------- docs/36.md | 14 +++++++------- docs/37.md | 8 ++++---- docs/38.md | 22 +++++++++++----------- docs/39.md | 22 +++++++++++----------- docs/40.md | 21 ++++++++++----------- docs/83.md | 6 +++--- 11 files changed, 89 insertions(+), 95 deletions(-) diff --git a/docs/31.md b/docs/31.md index ad68cf0..1fe0aef 100644 --- a/docs/31.md +++ b/docs/31.md @@ -8,11 +8,11 @@ ![Memory visual representation](img/751d3b0a0d5f994387d9626692b0926c.jpg) -记忆视觉表现 +内存视觉展示 在上面的表示中,4000、4004、4008 等表示内存插槽的地址,或者在与数组,数据的索引或内存位置进行的比较中。 这些“随机值”中的每一个代表 32 位。 由于每个内存插槽占用 32 位或 4 个字节,因此内存地址每次增加 4。 -通常,在 Java 和一般的编程中,有两种类型的可变范围– **全局**和**局部**。 全局变量是可以从程序中的任何地方访问的变量,而局部变量是只能在给定函数中创建它们的地方访问的变量。 因此,这两种不同类型的变量作用域存储在不同的存储区域中-**栈**和**数据。** +通常,在 Java 和一般的编程中,有两种类型的可变范围 – **全局**和**局部**。 全局变量是可以从程序中的任何地方访问的变量,而局部变量是只能在给定函数中创建它们的地方访问的变量。 因此,这两种不同类型的变量作用域存储在不同的存储区域中 - **栈**和**数据。** ![Memory regions](img/3977ced81858595e9eccbc2660b4817d.jpg) @@ -27,7 +27,7 @@ public void doSomething() { } ``` -在上面的简单 Java 示例中, v 存储在栈存储区域中。 这是因为 v 是局部变量。 +在上面的简单 Java 示例中,`v`存储在栈存储区域中。 这是因为`v`是局部变量。 ## 静态数据 @@ -41,7 +41,7 @@ public class Example { } ``` -在上面的 Java 示例中,globalVar 位于静态数据存储区中。 因为如您所见,即使未在其中创建方法,也可以通过该方法进行访问。 此外,可以在整个程序中对其进行访问。 +在上面的 Java 示例中,`globalVar`位于静态数据存储区中。 因为如您所见,即使未在其中创建方法,也可以通过该方法进行访问。 此外,可以在整个程序中对其进行访问。 ## 堆 @@ -68,12 +68,10 @@ public class Driver { } ``` -在上面的 Java 示例中,我们创建了 Person 类的新实例并将其存储在“ p”中,实际上,我们使用 Heap 区域为动态分配我们创建此类内存所需的内存。 使用 **新** 关键字的实例。 换句话说,它不固定为一定大小。 无论实例有多少字节,如果有足够的内存(可能),将创建该实例,并且该实例将仅保留创建该实例所需的字节数。 +在上面的 Java 示例中,我们创建了`Person`类的新实例并将其存储在`p`中,实际上,我们使用堆区域为动态分配我们创建此类内存所需的内存。 使用`new`关键字的实例。 换句话说,它不固定为一定大小。 无论实例有多少字节,如果有足够的内存(可能),将创建该实例,并且该实例将仅保留创建该实例所需的字节数。 -Java 在动态内存分配方面为我们省去了很多麻烦,因为在某些其他语言(例如 C)中,您必须手动分配内存并在不再需要该内存时手动“释放”相同的内存, 而在 Java 中,一切都在幕后发生,只需调用关键字 **new。** +Java 在动态内存分配方面为我们省去了很多麻烦,因为在某些其他语言(例如 C)中,您必须手动分配内存并在不再需要该内存时手动“释放”相同的内存, 而在 Java 中,一切都在幕后发生,只需调用关键字`new`。 我将建议以下有关如何调整 JVM 以使用特定内存量的教程 > [Java 增加内存](https://javatutorial.net/java-increase-memory) - -<iframe class="wp-embedded-content" data-secret="E5Uq3UeE34" frameborder="0" height="338" marginheight="0" marginwidth="0" sandbox="allow-scripts" scrolling="no" security="restricted" src="https://javatutorial.net/java-increase-memory/embed#?secret=E5Uq3UeE34" style="position: absolute; clip: rect(1px, 1px, 1px, 1px);" title="“Java Increase Memory” — Java Tutorial Network" width="600"></iframe> \ No newline at end of file diff --git a/docs/32.md b/docs/32.md index b81ffa3..805bc1e 100644 --- a/docs/32.md +++ b/docs/32.md @@ -12,39 +12,36 @@ Java [堆转储](https://www.ibm.com/support/knowledgecenter/en/SS3KLZ/com.ibm.j ## 1\. `jmap –XX:+HEAPDUMPONOUTOFMEMORYERROR` -值得注意的是,jmap 会将堆转储打印到特定的文件位置。 jmap 工具通常打包在 [JDK](https://javatutorial.net/install-java-8-jdk-on-ubuntu) 中。 您可以在以下文件夹中找到它:< JAVA_HOME > \ bin。 +值得注意的是,`jmap`会将堆转储打印到特定的文件位置。`jmap`工具通常打包在 [JDK](https://javatutorial.net/install-java-8-jdk-on-ubuntu) 中。 您可以在以下文件夹中找到它:`\bin`。 -要调用 jmap,请执行以下过程。 +要调用`jmap`,请执行以下过程。 -`jmap -dump: live, file=<file-path> <pid>` -,其中`pid`是 Java 进程 ID,将为其捕获堆转储 -。此外,`file-path`是其中打印堆转储的文件路径。 +`jmap -dump: live, file= `,其中`pid`是 Java 进程 ID,将为其捕获堆转储。此外,`file-path`是其中打印堆转储的文件路径。 -**请注意,传递**“实时”选择至关重要。 如果选项“通过”,则只会将活动对象写入堆转储文件。 但是,如果您无法通过该选项,则所有对象(包括未设置为垃圾收集的对象)都将被打印到堆转储中。 这样的错误会过多且不必要地增加其堆转储的大小。 通过将您的移动开发需求与 [Java Development Company](https://www.nearshore-it.eu/java-development/) 签订合同,可以避免此类错误。 +**请注意**,传递“实时”选择至关重要。 如果选项“通过”,则只会将活动对象写入堆转储文件。 但是,如果您无法通过该选项,则所有对象(包括未设置为垃圾收集的对象)都将被打印到堆转储中。 这样的错误会过多且不必要地增加其堆转储的大小。 通过将您的移动开发需求与 [Java Development Company](https://www.nearshore-it.eu/java-development/) 签订合同,可以避免此类错误。 ## 2\. `HeapDumpOnOutOfMemoryError` -当应用程序遇到 java.lang.OutOfMemoryError 时,捕获瞬时堆转储至关重要。 +当应用程序遇到`java.lang.OutOfMemoryError`时,捕获瞬时堆转储至关重要。 -这样的过程将有助于确定内存中占用的对象以及它们在 java.lang.OutOfMemoryError 发生时的位置所占用的空间量(百分比)。 +这样的过程将有助于确定内存中占用的对象以及它们在`java.lang.OutOfMemoryError`发生时的位置所占用的空间量(百分比)。 但是,由于操作和技术很多,操作组可能无法捕获堆转储。 此外,团队可能还重新启动了该应用程序。 因此,堆转储捕获已成为系统应用程序的关键方面,尤其是在涉及内存问题时。 -幸运的是,XX:+ HeapDumpOnOutOfMemoryError 选项将在该过程中提供帮助。 您只需在应用程序启动时传递系统属性(XX:+ HeapDumpOnOutOfMemoryError)。 然后, [JVM](https://javatutorial.net/jvm-explained) 将通过在 JVM 面临 OutOfMemoryError 的确切时间捕获堆转储来完成其余工作。 +幸运的是,`XX:+HeapDumpOnOutOfMemoryError`选项将在该过程中提供帮助。 您只需在应用程序启动时传递系统属性(`XX:+HeapDumpOnOutOfMemoryError`)。 然后, [JVM](https://javatutorial.net/jvm-explained) 将通过在 JVM 面临`OutOfMemoryError`的确切时间捕获堆转储来完成其余工作。 -值得注意的是,在上述情况下将捕获的头转储将打印在名为“ -XX:HeapDumpPath”的系统属性概述的位置中 +值得注意的是,在上述情况下将捕获的头转储将打印在名为`-XX:HeapDumpPath`的系统属性概述的位置中 ## 3\. `jcmd` -jcmd 工具用于发送命令请求以诊断 Java [JVM](https://javatutorial.net/jvm-explained) 。 同样,jcmd 工具包含在 JDK 软件包中。 您可以在名为\ bin 的文件夹中获取它。 +`jcmd`工具用于发送命令请求以诊断 Java [JVM](https://javatutorial.net/jvm-explained) 。 同样,`jcmd`工具包含在 JDK 软件包中。 您可以在名为`bin`的文件夹中获取它。 -这是调用 jcmd 时需要使用的过程; +这是调用`jcmd`时需要使用的过程; -1. 转到`jcmd <pid> GC.heap_dump <file-path>` -2. 其中 -3. pid:是一个 Java 进程 ID,将为其捕获堆转储 -4. 另外,file-path:是在其中打印堆转储的文件路径。 +1. 转到`jcmd GC.heap_dump ` +2. 其中`pid`:是一个 Java 进程 ID,将为其捕获堆转储 +4. 另外,`file-path`是在其中打印堆转储的文件路径。 结论 -在本文中,我讨论了可用于捕获 Java 堆转储的三个主要过程:(1)jmap – XX:+ HEAPDUMPONOUTOFMEMORYERROR(2)HeapDumpOnOutOfMemoryError 和(3)jcmd。 \ No newline at end of file +在本文中,我讨论了可用于捕获 Java 堆转储的三个主要过程:(1)`jmap –XX:+HEAPDUMPONOUTOFMEMORYERROR`(2)`HeapDumpOnOutOfMemoryError`和(3)`jcmd`。 \ No newline at end of file diff --git a/docs/33.md b/docs/33.md index 184d46c..63d5cbf 100644 --- a/docs/33.md +++ b/docs/33.md @@ -14,7 +14,7 @@ 因此,垃圾收集功能会找出这些对象并自动将其从内存中删除并删除它们,从而实现高效的内存使用和管理。 -如果要用 C 语言进行相同的垃圾收集和优化,则可以使用 free()函数,而在 C++中,则可以使用 delete()方法。 因此,Java 中此过程实现了自动化,从而为用户减少了麻烦。 +如果要用 C 语言进行相同的垃圾收集和优化,则可以使用`free()`函数,而在 C++ 中,则可以使用`delete()`方法。 因此,Java 中此过程实现了自动化,从而为用户减少了麻烦。 从技术上讲,Java 垃圾收集处理的是跟踪 [JVM(Java 虚拟机)](https://javatutorial.net/jvm-explained)堆空间中的每个对象,并删除(删除/取消分配)未使用的对象。 diff --git a/docs/34.md b/docs/34.md index 9065009..bd284ed 100644 --- a/docs/34.md +++ b/docs/34.md @@ -1,4 +1,4 @@ -# Java Mutex 示例 +# Java 互斥量示例 > 原文: [https://javatutorial.net/java-mutex-example](https://javatutorial.net/java-mutex-example) @@ -6,26 +6,26 @@ 想想一个队列。 不管长短,都没关系。 现在想想一辆正在出售游乐园门票的卡车。 一次一个人可以买票。 该人买了票后,就该排队了。 -这个小故事与理解 Mutex 有什么关系? 让我解释。 +这个小故事与理解互斥量有什么关系? 让我解释。 ![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg) -**Mutex 允许每个线程具有 1 个许可。** 换句话说,一次只能有 1 个线程可以访问资源。 在上面的类比中,两个人不能同时购买门票。 Mutex 也是如此。 它不是线程,而是人员,而是票证。 同样的事情或多或少.. +**互斥量允许每个线程具有 1 个许可**。换句话说,一次只能有 1 个线程可以访问资源。 在上面的类比中,两个人不能同时购买门票。互斥量也是如此。 它不是线程,而是人员,而是票证。 同样的事情或多或少.. -Mutex 与 Semaphore 略有不同,因此 **Semaphore 允许多个线程访问资源。** 的意思是,多个人可以同时购买门票。 +互斥量与`Semaphore`略有不同,因此`Semaphore`允许多个线程访问资源。意思是,多个人可以同时购买门票。 ![Mutex java example thread](img/66ac23d82b34151f8831186826308565.jpg) ## 构造器 -1. 公共[信号灯](https://javatutorial.net/java-semaphore-example)(国际许可); -2. 公共信号量(int 许可,布尔型公平); +1. `public Semaphore(int permits)`; +2. `public Semaphore(int permits, boolean fair)` -第一个构造函数是我们实际上可以区分 Mutex 和 Semaphore 的地方。 如果那里有 1 作为参数,则意味着将只允许 1 个线程获取锁。 请记住,由于它没有第二个参数**布尔公平**,因此您正在使 Semaphore 类以任何顺序访问任何线程。 +第一个构造函数是我们实际上可以区分互斥量和`Semaphore`的地方。 如果那里有 1 作为参数,则意味着将只允许 1 个线程获取锁。 请记住,由于它没有第二个参数`boolean fair`,因此您正在使`Semaphore`类以任何顺序访问任何线程。 -第二个构造函数如果传递 true(公平),则确保按线程请求访问并在队列中等待的顺序给出访问。 +第二个构造函数如果传递`true`(公平),则确保按线程请求访问并在队列中等待的顺序给出访问。 -## Mutex 基本代码实现 +## 互斥量基本代码实现 ```java import java.util.concurrent.Semaphore; @@ -100,10 +100,10 @@ Christie bought the ticket. How many people can buy tickets after Christie has finished buying the ticket: 1 ``` -从输出中可以看到,**当有人买票时,没有其他人可以买。** 这是显示以下内容的行之一: +从输出中可以看到,**当有人买票时,没有其他人可以买**。这是显示以下内容的行之一: Bob 仍在买票。 还有多少人可以和他一起买票: **0** 但是,在他“购买”了机票之后,其他人立即购买了机票。 -归根结底,它涉及 acquire()和 release()。 Acquire()是指该人开始“购买机票”的时间,release()是指该人“购买机票”的时间。 \ No newline at end of file +归根结底,它涉及`acquire()`和`release()`。`acquire()`是指该人开始“购买机票”的时间,`release()`是指该人“购买机票”的时间。 \ No newline at end of file diff --git a/docs/35.md b/docs/35.md index fa481b7..8e56100 100644 --- a/docs/35.md +++ b/docs/35.md @@ -4,7 +4,7 @@ 信号量可用于限制并发线程的数量,并且实质上,此类维护一组许可。 -Acquire()从信号量获取许可,然后 release()将许可返回信号量。 如果没有许可证,则 acuire()将阻塞直到可用 +`acquire()`从信号量获取许可,然后`release()`将许可返回信号量。 如果没有许可证,则`acuire()`将阻塞直到可用 信号量用于控制对特定资源的访问。 @@ -12,22 +12,22 @@ Acquire()从信号量获取许可,然后 release()将许可返回信 **工作流程** -信号量设置为一个计数值。 然后线程尝试获取许可,如果计数为 0 或小于 0,则线程将被阻塞,并且它将等待下一个许可(如果有)。 这将一直保持下去,直到 count 大于 0。如果是,则信号量将提供对线程资源的访问。 然后线程将释放许可,计数将增加 1。 +信号量设置为一个计数值。 然后线程尝试获取许可,如果计数为 0 或小于 0,则线程将被阻塞,并且它将等待下一个许可(如果有)。 这将一直保持下去,直到数量大于 0。如果是,则信号量将提供对线程资源的访问。 然后线程将释放许可,计数将增加 1。 ## 构造器 -1. 信号量(int 许可):使用给定数量的许可和不公平的公平设置创建一个信号量 -2. 信号量(int 许可,布尔值公平):创建具有给定许可数量和给定公平性设置的信号量 +1. `Semaphore(int permits)`:使用给定数量的许可和不公平的公平设置创建一个信号量 +2. `Semaphore(int permits, boolean fair)`:创建具有给定许可数量和给定公平性设置的信号量 ## 主要方法 -1. void acquisition():从当前信号量获取许可,阻塞直到可用,否则线程被中断。 -2. void Acquisition(int permits):从当前信号量获取指定的许可数量,直到所有可用或线程中断为止一直阻塞。 -3. int availablePermites():返回当前信号量中可用的当前许可数量 +1. `void acquire()`:从当前信号量获取许可,阻塞直到可用,否则线程被中断。 +2. `void acquire(int permits)`:从当前信号量获取指定的许可数量,直到所有可用或线程中断为止一直阻塞。 +3. `int availablePermites()`:返回当前信号量中可用的当前许可数量 -要查看所有方法,请在处单击[。 您将被重定向到 Oracle 官方文档。](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html) +要查看所有方法,[请单击此处,您将被重定向到 Oracle 官方文档](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html)。 -信号量可用于锁定对特定资源的访问。 每个线程都必须请求“权限”,因此需要在访问资源之前调用方法 acquire()。 当线程不再需要资源时,它必须调用 release()来释放锁。 +信号量可用于锁定对特定资源的访问。 每个线程都必须请求“权限”,因此需要在访问资源之前调用方法`acquire()`。 当线程不再需要资源时,它必须调用`release()`来释放锁。 ```java import java.util.concurrent.Semaphore; @@ -66,9 +66,9 @@ Available permits: 1 Available permits: 0 ``` -从上面的示例中可以看到,当您调用 release()时,您正在向 Semaphore 实例添加许可。 当您调用 acquire()时,您正在删除 permit()。 如果没有许可证,而您打电话给获取,它将等待直到许可证被释放,因此在上例中将永远不会执行最后一个打印语句。 +从上面的示例中可以看到,当您调用`release()`时,您正在向`Semaphore`实例添加许可。 当您调用`acquire()`时,您正在删除`permit()`。 如果没有许可证,而您打电话给获取,它将等待直到许可证被释放,因此在上例中将永远不会执行最后一个打印语句。 -如果您有 1 个许可,然后又有一个 Acquisition()调用,紧接着是一个 release()调用,则称为**锁。** +如果您有 1 个许可,然后又有一个`acquire()`调用,紧接着是一个`release()`调用,则称为锁。 ```java import java.util.concurrent.Semaphore; diff --git a/docs/36.md b/docs/36.md index 5fb20a1..29a75d9 100644 --- a/docs/36.md +++ b/docs/36.md @@ -8,16 +8,16 @@ 有两种创建并行流的方法: -* 通过使用 parallelStream()方法 -* 通过使用 parallel()方法 +* 通过使用`parallelStream()`方法 +* 通过使用`parallel()`方法 当您使用并行流时,它们实际上会使用更多的 CPU 能力,这将使整个输出或处理(如果您愿意)的整体速度更快。 更快! 另外,如果您不使用并行流进行大型计算,则您的程序将仅使用 16 个内核中的 1 个内核。 多么低效! -**订单** +## 顺序 并行流将问题分为多个小子集(或子问题),它们可以同时解决(不同于顺序排列的顺序,在这些子集中一个一个地执行每个小问题)。 在计算了子问题之后,将所有对它们的解决方案组合在一起。 -**如何实现** +## 如何实现 Java 允许您通过使用诸如 map 之类的聚合操作来实现并行流。 @@ -51,11 +51,11 @@ public class Main { } ``` -在此示例中,我们有一个示例方法,该方法仅循环 10000 次并将 i 加到 n。 最后,我们简单地返回 n。 在我们的主要函数中,我们创建一个包含整数的 [ArrayList](https://javatutorial.net/java-arraylist-example) 。 然后我们创建一个巨大的循环,循环 1000000 次,然后将每个增量 i * 6 加到 arraylist 中。 添加完之后,我们得到了这两个打印语句,它们指出这个大循环已经完成。 +在此示例中,我们有一个示例方法,该方法仅循环 10000 次并将`i`加到`n`。 最后,我们简单地返回`n`。 在我们的主要函数中,我们创建一个包含整数的[`ArrayList`](https://javatutorial.net/java-arraylist-example)。 然后我们创建一个巨大的循环,循环 1000000 次,然后将每个增量`i * 6`加到`arraylist`中。 添加完之后,我们得到了这两个打印语句,它们指出这个大循环已经完成。 -在这些打印语句下面是有趣的部分。 更具体地说,这是我们使用映射函数创建并行流的地方。 我们在 arraylist 上调用 parallelStream(),对于 arraylist 中的每个 i,我们都在调用计算函数,并将 arraylist 的元素作为参数传递。 最后,我们将所有结果结合在一起。 +在这些打印语句下面是有趣的部分。 更具体地说,这是我们使用映射函数创建并行流的地方。 我们在`arraylist`上调用`parallelStream()`,对于`arraylist`中的每个`i`,我们都在调用计算函数,并将`arraylist`的元素作为参数传递。 最后,我们将所有结果结合在一起。 -**何时应使用并行流** +## 何时应使用并行流 * 当有大量数据要处理时 * 如果循序渐进的方法使您付出了代价 diff --git a/docs/37.md b/docs/37.md index 567e926..0ee5e01 100644 --- a/docs/37.md +++ b/docs/37.md @@ -26,7 +26,7 @@ 同步块用于线程同步。 -Synchronized 关键字用于标识 Java 中的同步块,并基于某些对象进行同步。 其背后的主要概念是,在同一对象上同步的所有同步块一次只能在其中一个线程内执行,这会阻止多个线程同时运行和执行。 尝试进入同步块的所有其他线程将被阻止,直到同步块内的线程退出该块为止。 +`synchronized`关键字用于标识 Java 中的同步块,并基于某些对象进行同步。 其背后的主要概念是,在同一对象上同步的所有同步块一次只能在其中一个线程内执行,这会阻止多个线程同时运行和执行。 尝试进入同步块的所有其他线程将被阻止,直到同步块内的线程退出该块为止。 共享资源保留在此同步块内,以便在给定时间点只有一个线程可以访问特定资源。 @@ -110,7 +110,7 @@ public class Tests { ``` -<u>输出:</u>(每次运行都会产生不同的结果) +输出:(每次运行都会产生不同的结果) ```java Starting Thread - 1 @@ -129,7 +129,7 @@ Thread Thread - 1  exiting. Thread Thread - 2  exiting. ``` -<u>相同的示例,但是这次具有线程同步:</u> +相同的示例,但是这次具有线程同步: ```java class Countings { @@ -192,7 +192,7 @@ public class Testings{ ``` -<u>输出:</u>(我们看到的输出是同步的,并且每次执行程序都是相同的) +输出:(我们看到的输出是同步的,并且每次执行程序都是相同的) ```java Starting Thread - 1 diff --git a/docs/38.md b/docs/38.md index e30e5cd..079552a 100644 --- a/docs/38.md +++ b/docs/38.md @@ -18,9 +18,9 @@ ## `Executor`,`Runnable`和`ExecutorService` -Java 提供了 Executor 框架,这意味着您只需要实现 Runnable 对象并将其发送给 executor 即可执行。 +Java 提供了`Executor`框架,这意味着您只需要实现`Runnable`对象并将其发送给执行器即可执行。 -要使用线程池,首先我们需要创建一个 ExecutorService 对象并将任务传递给它。 ThreadPoolExecutor 类设置核心和最大池大小。 然后,可运行对象将顺序执行。 +要使用线程池,首先我们需要创建一个`ExecutorService`对象并将任务传递给它。`ThreadPoolExecutor`类设置核心和最大池大小。 然后,可运行对象将顺序执行。 ## 不同的`Executor`线程池方法 @@ -32,7 +32,7 @@ newCachedThreadPool() - creates a thread pool that creates new threads if needed newSingleThreadExecutor() - creates a single thread ``` -ExecutorService 接口包含许多方法,这些方法用于控制任务的进度并管理服务的终止。 您可以使用 Future 实例控制任务的执行。 有关如何使用 Future 的示例: +`ExecutorService`接口包含许多方法,这些方法用于控制任务的进度并管理服务的终止。 您可以使用`Future`实例控制任务的执行。 有关如何使用`Future`的示例: ```java ExecutorService execService = Executors.newFixedThreadPool(6); @@ -40,13 +40,13 @@ Future future = execService.submit(() -> "Example"); String result = future.get(); ``` -ThreadPoolExecutor 使您可以实现具有许多参数的可扩展线程池,这些参数包括 corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,处理程序,threadFactor。 但是,corePoolSize,maximumPoolSize 和 keepAliveTime 是主要变量,因为它们在每个构造函数中都使用。 +`ThreadPoolExecutor`使您可以实现具有许多参数的可扩展线程池,这些参数包括`corePoolSize`,`maximumPoolSize`,`keepAliveTime`,`unit`,`workQueue`,`handler`,`threadFactor`。 但是,`corePoolSize`,`maximumPoolSize`和`keepAliveTime`是主要变量,因为它们在每个构造函数中都使用。 -corePoolSize 是要保留在池中的线​​程数,即使它们处于空闲状态,除非设置了 allowCoreThreadTimeOut。 +`corePoolSize`是要保留在池中的线​​程数,即使它们处于空闲状态,除非设置了`allowCoreThreadTimeOut`。 -maximumPoolSize 是池中允许的最大线程数。 +`maximumPoolSize`是池中允许的最大线程数。 -keepAliveTime 是当线程数大于内核数时,这是多余的空闲线程将在终止之前等待新任务的最长时间。 +`keepAliveTime`是当线程数大于内核数时,这是多余的空闲线程将在终止之前等待新任务的最长时间。 有关其他参数的更多信息,请访问[原始 Oracle 文档](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html)。 @@ -59,7 +59,7 @@ keepAliveTime 是当线程数大于内核数时,这是多余的空闲线程将 3. 将任务传递给执行程序池 4. 关闭执行程序池 -**Task.java** +`Task.java` ```java import java.text.SimpleDateFormat; @@ -100,7 +100,7 @@ public class Task implements Runnable { ``` -**Main.java** +`Main.java` ```java import java.text.SimpleDateFormat; @@ -171,7 +171,7 @@ task 5 completed **上面的代码实现的细分:** -Task.java 表示任务类。 每个任务都有一个名称实例变量,并且每个任务都使用构造函数实例化。 此类有 1 个方法,称为运行。 在 run 方法的主体内,有一个 for 循环,该循环根据存在的任务数进行迭代。 在我们的例子中,有 5 个任务,这意味着它将运行 5 次。 第一次迭代,显示当前任务初始化的时间。 其他迭代,打印执行时间。 打印完成后,有一个 Thread.sleep()方法调用,该方法用于以 1 秒的延迟显示每个迭代消息。 **注意**,像这样调用的方法名称“ run” 非常重要,因为它是来自 Task 类正在实现的 Runnable 的抽象方法。 +`Task.java`表示任务类。 每个任务都有一个名称实例变量,并且每个任务都使用构造函数实例化。 此类有 1 个方法,称为`run`。 在`run`方法的主体内,有一个`for`循环,该循环根据存在的任务数进行迭代。 在我们的例子中,有 5 个任务,这意味着它将运行 5 次。 第一次迭代,显示当前任务初始化的时间。 其他迭代,打印执行时间。 打印完成后,有一个`Thread.sleep()`方法调用,该方法用于以 1 秒的延迟显示每个迭代消息。 **注意**,像这样调用的方法名称`run`非常重要,因为它是来自`Task`类正在实现的`Runnable`的抽象方法。 仅在池中的某个胎面变得空闲时才执行任务 4 和 5。 在此之前,额外的任务将放置在队列中。 @@ -179,4 +179,4 @@ Task.java 表示任务类。 每个任务都有一个名称实例变量,并且 ## 线程池何时有用 -组织服务器应用程序时。 如本文开头所述,在组织服务器应用程序时非常有用,因为使用线程池非常有效,就像有许多任务一样,它会自动将它们放入队列中。 不仅如此,它还可以防止内存不足,或者至少可以显着减慢这样做的速度。 使用 ExecutorService 使其更易于实现。 \ No newline at end of file +组织服务器应用程序时。 如本文开头所述,在组织服务器应用程序时非常有用,因为使用线程池非常有效,就像有许多任务一样,它会自动将它们放入队列中。 不仅如此,它还可以防止内存不足,或者至少可以显着减慢这样做的速度。 使用`ExecutorService`使其更易于实现。 \ No newline at end of file diff --git a/docs/39.md b/docs/39.md index fd1683b..5cfca87 100644 --- a/docs/39.md +++ b/docs/39.md @@ -2,11 +2,11 @@ > 原文: [https://javatutorial.net/threadlocal-java-example](https://javatutorial.net/threadlocal-java-example) -ThreadLocal 是提供线程局部变量的类,用于实现线程安全。 存储的数据只能由特定线程访问。 +`ThreadLocal`是提供线程局部变量的类,用于实现线程安全。 存储的数据只能由特定线程访问。 ![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg) -ThreadLocal 扩展了 Object 类,并提供了线程限制,它是局部变量的“一部分”。 +`ThreadLocal`扩展了`Object`类,并提供了线程限制,它是局部变量的“一部分”。 ## 创建`ThreadLocal`变量 @@ -14,18 +14,18 @@ ThreadLocal 扩展了 Object 类,并提供了线程限制,它是局部变量 ThreadLocal threadLocalExample = new ThreadLocal(); ``` -上面代码中 ThreadLocal 对象的实例化仅需要针对每个线程进行。 +上面代码中`ThreadLocal`对象的实例化仅需要针对每个线程进行。 -就像大多数类一样,一旦有了 ThreadLocal 的实例,就可以在其上调用方法。 一些方法是: +就像大多数类一样,一旦有了`ThreadLocal`的实例,就可以在其上调用方法。 一些方法是: -1. get():返回此线程局部变量的当前线程副本中的值 -2. initialValue():返回当前线程局部变量的当前线程初始值 -3. remove():从当前线程中删除当前线程局部变量的值 -4. set(T value):将当前线程局部变量的当前线程副本设置为指定值 +1. `get()`:返回此线程局部变量的当前线程副本中的值 +2. `initialValue()`:返回当前线程局部变量的当前线程初始值 +3. `remove()`:从当前线程中删除当前线程局部变量的值 +4. `set(T value)`:将当前线程局部变量的当前线程副本设置为指定值 -有关这些方法的更多详细信息,请访问原始 [Oracle 文档。](https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html) +有关这些方法的更多详细信息,请访问原始 [Oracle 文档](https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html)。 -ThreadLocal 实例是希望将状态与线程相关联的类中的私有静态字段(在大多数情况下) +`ThreadLocal`实例是希望将状态与线程相关联的类中的私有静态字段(在大多数情况下) ## 实现示例 @@ -81,4 +81,4 @@ After remove: null ## 分解 -上面的代码显示了两种使它起作用的方法:一种是通过拥有 Runnable 对象并将其传递给 Thread 实例,然后覆盖 run()方法,或者您可以简单地创建一个 ThreadLocal 实例并为其设置值,然后 可以获取或删除它。 从上面的示例中可以看到,即使它是相同的变量(局部变量),也可以包含不同的值。 在第一种情况下,它包含值“ First”。 在第二种情况下,它包含值“ Second”。 对于其他实现,我只显示了一个线程。 但是,每个线程都是独立的–意味着,如果您要创建另一个 Thread 实例(例如 thread2),并对其进行 start(),它将独立运行,并且与其他 Thread 实例变量无关。 要进行检查,可以在静态类中创建一个 ThreadLocal 实例,然后在重写的 run()方法中创建一个随机数,然后使用 set()方法将其传递给当前线程。 您将看到,如果您在两个或多个不同的线程上调用它,则它们都将具有不同的值。 \ No newline at end of file +上面的代码显示了两种使它起作用的方法:一种是通过拥有`Runnable`对象并将其传递给`Thread`实例,然后覆盖`run()`方法,或者您可以简单地创建一个`ThreadLocal`实例并为其设置值,然后 可以获取或删除它。 从上面的示例中可以看到,即使它是相同的变量(局部变量),也可以包含不同的值。 在第一种情况下,它包含值`"First"`。 在第二种情况下,它包含值`"Second"`。 对于其他实现,我只显示了一个线程。 但是,每个线程都是独立的–意味着,如果您要创建另一个`Thread`实例(例如`thread2`),并对其进行`start()`,它将独立运行,并且与其他`Thread`实例变量无关。 要进行检查,可以在静态类中创建一个`ThreadLocal`实例,然后在重写的`run()`方法中创建一个随机数,然后使用`set()`方法将其传递给当前线程。 您将看到,如果您在两个或多个不同的线程上调用它,则它们都将具有不同的值。 \ No newline at end of file diff --git a/docs/40.md b/docs/40.md index deb291d..4dec278 100644 --- a/docs/40.md +++ b/docs/40.md @@ -6,23 +6,23 @@ ## 活锁 -Java 中的 Livelock 是一种递归条件,其中两个或多个线程不断重复一段特定的代码。 +Java 中的活锁是一种递归条件,其中两个或多个线程不断重复一段特定的代码。 -当一个线程不断响应另一个线程并且另一个线程也执行相同操作时,就会发生 Livelock。 +当一个线程不断响应另一个线程并且另一个线程也执行相同操作时,就会发生活锁。 要对其进行分解,我们可以总结以下几点: * 一个线程响应另一个线程的行为而运行,而另一个线程也响应先前的线程而运行,则可能发生活锁。 -* Livelock 线程无法继续进行。 +* 活锁线程无法继续进行。 * 线程没有被阻塞; 他们只是忙于互相回应。 -Livelock 也被称为资源匮乏的特例 +活锁也被称为资源匮乏的特例 让我们通过将其与现实世界联系起来来理解该概念。 考虑两辆车在狭窄桥梁的相对两侧。 一次只能乘一辆车通过桥。 这两辆车的驾驶员都很有礼貌,正在等待对方先通过桥。 他们互相鸣叫,让他们知道他们想让对方先通过。 但是,两者都没有越过桥梁并互相鸣喇叭。 这种情况类似于活锁。 现在,通过一些编码来尝试这种实际情况: -<u>第一辆等待过桥的汽车的等级:</u> +第一辆等待过桥的汽车的等级: ```java public class Car1 { @@ -50,7 +50,7 @@ public class Car1 { ``` -<u>等待通过桥的第二辆车的类别:</u> +等待通过桥的第二辆车的类别: ```java public class Car2 { @@ -81,7 +81,7 @@ public class Car2 { ``` -<u>主要测试类别:</u> +主要测试类别: ```java public class BridgeCheck { @@ -106,7 +106,7 @@ public class BridgeCheck { ``` -<u>输出:</u> +输出: 这导致了非终止循环。 @@ -120,7 +120,7 @@ public class BridgeCheck { 图:死锁状态 -<u>让我们看一下发生死锁的情况:</u> +让我们看一下发生死锁的情况: ```java public class DeadlockExample{ @@ -149,9 +149,8 @@ private static String B = "Something B"; 考虑两个线程 T1 和 T2,T1 获取 A 并等待 B 完成其功能。 但是,T2 获取 B 并等待 A 完成其自身的功能。 在这里,T1 和 T2 正在等待被其他线程锁定的资源。 因此,这是一个僵局方案。 -**<u>,</u>** -**<u>一起避免死锁:</u>** +## 避免死锁: * 第一个建议是避免同时使用多线程,但这在许多情况下可能不切实际。 因此,这种解决方案不是很明智。 * 分析并确保在事先访问资源时没有锁。 diff --git a/docs/83.md b/docs/83.md index b661257..4b9f27c 100644 --- a/docs/83.md +++ b/docs/83.md @@ -35,7 +35,7 @@ Java 中有 4 种引用类型: * 弱引用还广泛用于 [WeakHashMap](https://javatutorial.net/java-weakhashmap-example) 类中。 这是 Map 接口的实现,其中每个键值都存储为弱引用。 键值对扩展了 WeakReference 类。 因此,垃圾收集器删除此键也会导致实体也被删除。 -<u>代码示例:</u> +代码示例: 私有静态类 TryingOut < K,V >扩展了 WeakReference <对象>实现 Map.Entry < K,V > @@ -43,7 +43,7 @@ Java 中有 4 种引用类型: ## 实现弱引用: -<u>java.lang.ref.WeakReference</u> 类在处理和创建弱引用时使用。 +java.lang.ref.WeakReference 类在处理和创建弱引用时使用。 可以使用弱引用的一种实际的实际场景是在建立数据库连接时使用,当使用数据库的应用程序关闭时,垃圾收集器可能会清除该数据库连接。 @@ -84,7 +84,7 @@ public class TryingOutWeak ``` -<u>代码的输出:</u> +代码的输出: 这被打印在屏幕上 -- GitLab