Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
jtn-zh
提交
5028e799
J
jtn-zh
项目概览
OpenDocCN
/
jtn-zh
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jtn-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
5028e799
编写于
11月 26, 2019
作者:
W
wizardforcel
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
2019-11-26 18:42:18
上级
0c9e6018
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
89 addition
and
95 deletion
+89
-95
docs/31.md
docs/31.md
+6
-8
docs/32.md
docs/32.md
+14
-17
docs/33.md
docs/33.md
+1
-1
docs/34.md
docs/34.md
+11
-11
docs/35.md
docs/35.md
+11
-11
docs/36.md
docs/36.md
+7
-7
docs/37.md
docs/37.md
+4
-4
docs/38.md
docs/38.md
+11
-11
docs/39.md
docs/39.md
+11
-11
docs/40.md
docs/40.md
+10
-11
docs/83.md
docs/83.md
+3
-3
未找到文件。
docs/31.md
浏览文件 @
5028e799
...
...
@@ -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
docs/32.md
浏览文件 @
5028e799
...
...
@@ -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
)
中。 您可以在以下文件夹中找到它:
`<JAVA_HOME>\bin`
。
要调用
jmap
,请执行以下过程。
要调用
`jmap`
,请执行以下过程。
`jmap -dump: live, file=<file-path> <pid>`
,其中
`pid`
是 Java 进程 ID,将为其捕获堆转储
。此外,
`file-path`
是其中打印堆转储的文件路径。
`jmap -dump: live, file=<file-path> <pid>`
,其中
`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 <pid> GC.heap_dump <file-path>`
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
docs/33.md
浏览文件 @
5028e799
...
...
@@ -14,7 +14,7 @@
因此,垃圾收集功能会找出这些对象并自动将其从内存中删除并删除它们,从而实现高效的内存使用和管理。
如果要用 C 语言进行相同的垃圾收集和优化,则可以使用
free()函数,而在 C++中,则可以使用 delete()
方法。 因此,Java 中此过程实现了自动化,从而为用户减少了麻烦。
如果要用 C 语言进行相同的垃圾收集和优化,则可以使用
`free()`
函数,而在 C++ 中,则可以使用
`delete()`
方法。 因此,Java 中此过程实现了自动化,从而为用户减少了麻烦。
从技术上讲,Java 垃圾收集处理的是跟踪
[
JVM(Java 虚拟机)
](
https://javatutorial.net/jvm-explained
)
堆空间中的每个对象,并删除(删除/取消分配)未使用的对象。
...
...
docs/34.md
浏览文件 @
5028e799
# 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
docs/35.md
浏览文件 @
5028e799
...
...
@@ -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
;
...
...
docs/36.md
浏览文件 @
5028e799
...
...
@@ -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`
的元素作为参数传递。 最后,我们将所有结果结合在一起。
**何时应使用并行流**
## 何时应使用并行流
*
当有大量数据要处理时
*
如果循序渐进的方法使您付出了代价
...
...
docs/37.md
浏览文件 @
5028e799
...
...
@@ -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
...
...
docs/38.md
浏览文件 @
5028e799
...
...
@@ -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<String> 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
docs/39.md
浏览文件 @
5028e799
...
...
@@ -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
docs/40.md
浏览文件 @
5028e799
...
...
@@ -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>**
## 避免死锁:
*
第一个建议是避免同时使用多线程,但这在许多情况下可能不切实际。 因此,这种解决方案不是很明智。
*
分析并确保在事先访问资源时没有锁。
...
...
docs/83.md
浏览文件 @
5028e799
...
...
@@ -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
>
代码的输出:
这被打印在屏幕上
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录