socket.close()。
-
- 这里涉及TCP协议以及HTTP 1.1的长连接,先不详细解释。这里我们简单地使用一个Header就可以断开请求了。
-
-```java
-bw.write("Connection: close\r\n");
-```
-
- 把上面这一段代码复制到前面一段代码的Header部分即可。perfect!
From eb9f790b6ad11d92abf6b05f62dcd36e17c57f66 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Mon, 14 Jul 2014 08:52:47 +0800
Subject: [PATCH 002/524] =?UTF-8?q?Update=2027.Java=E5=8A=A0=E5=AF=86?=
=?UTF-8?q?=E8=A7=A3=E5=AF=86=E4=B9=8B=E5=AF=B9=E7=A7=B0=E5=8A=A0=E5=AF=86?=
=?UTF-8?q?=E7=AE=97=E6=B3=95.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...47\260\345\212\240\345\257\206\347\256\227\346\263\225.md" | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git "a/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md" "b/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
index 567e86e..6d65f53 100644
--- "a/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
+++ "b/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
@@ -6,7 +6,7 @@
**对称加密算法的安全基于密钥的保密,所以密钥的安全与否决定了加密信息的安全!**
-虽然说**对称加密算法**不适用于安全要求较高的场合,对是对于一般应用来说,这已经足够了。与此同时,对称加密的速度远由于非对称加密,所以还是很多场景适用对称加密。
+虽然说**对称加密算法**不适用于安全要求较高的场合,对是对于一般应用来说,这已经足够了。与此同时,对称加密的速度远低于非对称加密,所以还是很多场景适用对称加密。
对称加密的速度比公钥加密快很多,在很多场合都需要对称加密。
@@ -111,4 +111,4 @@ public void decrypt() throws InvalidKeyException, NoSuchAlgorithmException, NoSu
* 密码学:http://zh.wikipedia.org/wiki/%E5%AF%86%E7%A2%BC%E5%AD%B8
* 经典密码:http://zh.wikipedia.org/wiki/%E7%B6%93%E5%85%B8%E5%AF%86%E7%A2%BC
* DES:http://zh.wikipedia.org/wiki/%E8%B3%87%E6%96%99%E5%8A%A0%E5%AF%86%E6%A8%99%E6%BA%96
-* 3DES:http://zh.wikipedia.org/wiki/3DES
\ No newline at end of file
+* 3DES:http://zh.wikipedia.org/wiki/3DES
From 7d829cea8acfd020ea5249b0df869885e7a776e9 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Mon, 14 Jul 2014 08:53:56 +0800
Subject: [PATCH 003/524] =?UTF-8?q?Update=2027.Java=E5=8A=A0=E5=AF=86?=
=?UTF-8?q?=E8=A7=A3=E5=AF=86=E4=B9=8B=E5=AF=B9=E7=A7=B0=E5=8A=A0=E5=AF=86?=
=?UTF-8?q?=E7=AE=97=E6=B3=95.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md" | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git "a/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md" "b/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
index 6d65f53..fa4690c 100644
--- "a/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
+++ "b/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
@@ -36,7 +36,7 @@ IDEA(International Data Encryption Algorithm,国际数据加密标准)是
在加密之前,我们先要生成加密算法对应的密钥。我们之前所说的密钥长度都是基于位元为单位的。例如128位的密钥,则该密钥占用128个位元,以一个字节八位元,128密钥占用128 / 8 = 16个字节。使用byte[]数组存放,则byte[]的长度为16。
-为了方便存储和传输,我们通常使用Base64对密钥的字节组数进行编码。而ASCII编码有很多字符是不可打印的,所以不建议使用ASCII。当然你可以使用ASCII,当时很容易在存储或传输过程中丢失字节(在计算器中存储和传输没有问题,但是使用纸质就歇菜了)。当然你可以使用其他方式和编码,一般情况下都是使用Base64,约定俗成。
+为了方便存储和传输,我们通常使用Base64对密钥的字节组数进行编码。而ASCII编码有很多字符是不可打印的,所以不建议使用ASCII。当然你可以使用ASCII,但是很容易在存储或传输过程中丢失字节(在计算器中存储和传输没有问题,但是使用纸质就歇菜了)。当然你可以使用其他方式和编码,一般情况下都是使用Base64,约定俗成。
Java中使用`KeyGenerator`类来生成密钥。如下:
From 882c605199271acb614fba2bf3b7a15ba64a267a Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Mon, 14 Jul 2014 08:55:25 +0800
Subject: [PATCH 004/524] =?UTF-8?q?Update=2027.Java=E5=8A=A0=E5=AF=86?=
=?UTF-8?q?=E8=A7=A3=E5=AF=86=E4=B9=8B=E5=AF=B9=E7=A7=B0=E5=8A=A0=E5=AF=86?=
=?UTF-8?q?=E7=AE=97=E6=B3=95.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md" | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git "a/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md" "b/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
index fa4690c..caaaded 100644
--- "a/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
+++ "b/27.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
@@ -58,7 +58,7 @@ public void generateKey() throws NoSuchAlgorithmException {
Cipher是JCA中用于加密解密的类,它同时负责数据的加密与解密。在初始化时,需要为Cipher指定是加密或是解密模式。
-加密与加密的过程直接操作的是数据的字节数组,由于字符在JVM中是以unicode形式存在的,字符串的不同编码的字节数组序列是一样的,例如UTF-8和GBK的字节序列就不一样。所以在加密之前或加密之后需要将字符编码进行编码与解码。当然,这不是必须的,你可以使用系统默认的ASCII字符编码,只要统一即可。
+加密与加密的过程直接操作的是数据的字节数组,由于字符在JVM中是以unicode形式存在的,字符串的不同编码的字节数组序列是不一样的,例如UTF-8和GBK的字节序列就不一样。所以在加密之前或加密之后需要将字符编码进行编码与解码。当然,这不是必须的,你可以使用系统默认的ASCII字符编码,只要统一即可。
数据加密后是以字节数组存在的,跟密钥类似,为了方面存储和传输,我们将加密后的结果转为Base64表示形式。
From a74fa79ded72cc639d6afbe3f4f3ff1b46f12e95 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Mon, 14 Jul 2014 08:57:14 +0800
Subject: [PATCH 005/524] =?UTF-8?q?Update=2028.Java=E5=8A=A0=E5=AF=86?=
=?UTF-8?q?=E8=A7=A3=E5=AF=86=E4=B9=8B=E9=9D=9E=E5=AF=B9=E7=A7=B0=E5=8A=A0?=
=?UTF-8?q?=E5=AF=86=E7=AE=97=E6=B3=95.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...47\260\345\212\240\345\257\206\347\256\227\346\263\225.md" | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git "a/28.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\351\235\236\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md" "b/28.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\351\235\236\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
index 025fe05..0398372 100644
--- "a/28.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\351\235\236\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
+++ "b/28.Java\345\212\240\345\257\206\350\247\243\345\257\206\344\271\213\351\235\236\345\257\271\347\247\260\345\212\240\345\257\206\347\256\227\346\263\225.md"
@@ -10,7 +10,7 @@
###28.2.1 典型非对称加密算法:RSA
-RSA算法密钥的长度为512位至65535位之间,且必须是64的倍数。Java6默认的RSA算法的密钥长度是1014位。
+RSA算法密钥的长度为512位至65535位之间,且必须是64的倍数。Java6默认的RSA算法的密钥长度是1024位。
###28.2.2 常用非对称加密算法:EIGamal
@@ -74,4 +74,4 @@ public void t6_decrypt() throws NoSuchAlgorithmException, InvalidKeySpecExceptio
}
```
-##28.4 参考资料
\ No newline at end of file
+##28.4 参考资料
From 87c5d40ab30e1f5efbc837cb5efc9cd299f326ea Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 28 Aug 2014 18:42:44 +0800
Subject: [PATCH 006/524] Published with https://stackedit.io/
---
30.Java Runtime Data Areas.md | 70 +++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100644 30.Java Runtime Data Areas.md
diff --git a/30.Java Runtime Data Areas.md b/30.Java Runtime Data Areas.md
new file mode 100644
index 0000000..c085782
--- /dev/null
+++ b/30.Java Runtime Data Areas.md
@@ -0,0 +1,70 @@
+#30.Java Runtime Data Areas.md
+
+##30.1 运行时数据区(Runtime Data Areas)
+Java虚拟机为程序的运行提供了各种不同的数据区,部分数据区与JVM的生命周期一致(随JVM启动而分配,JVM退出而释放),而另一部分则跟线程绑定,随着线程的启动和退出进行分配和释放。
+
+###30.1.1 程序计数器(Program Counter Rigister)
+Java虚拟机支持多个线程在同一时刻运行。每一个Java虚拟机线程拥有自己的程序计数器。在任意时刻,任意线程都处于一个方法中(称为当前方法(current method)),如果是该方法是**非本地方法(not native method)**,则该程序计数器记录着**Java虚拟机执行的当前指令的地址**。而如果该方法为**本地方法(native method)**,则该程序计数器为undefined。
+
+##30.1.2 Java虚拟机栈(Java Virtual Machine Stacks)
+每个Java虚拟机线程都拥有各自的**Java虚拟机栈**,并与线程同时被创建。Java虚拟机栈用于存储**帧(frames)**。Java虚拟机栈跟传统语言的栈相似:存储局部变量、结果,同时参与方法的调用和返回。
+Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.
+
+在第一版的Java虚拟机规范中,**Java虚拟机栈**做为**Java栈** 为人们所熟知。这个规范允许Java虚拟机栈是固定的大小或根据需要通过计算来动态地扩展和收缩。如果Java虚拟机堆的大小是固定的,(If the Java Virtual Machine stacks are of a fixed size, the size of each Java Virtual Machine stack may be chosen independently when that stack is created.)
+
+Java虚拟的实现可以提供让程序员或用户来控制Java虚拟栈初始大小,并且,可以让Java虚拟机栈在最小值和最大值的限制范围内根据实际需要动态地拓展或收缩。
+
+以下异常情况与Java虚拟栈相关:
+* 如果线程需要的Java虚拟机栈大小超过限额,则抛出**StackOverflowError**。
+* 如果Java虚拟机栈被设置为可动态拓展,当拓展时由于受限于物理内存的限制而无法实现拓展时,则抛出**OutOfMemoryError**。
+
+
+2.5.3. Heap
+
+The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.
+
+The heap is created on virtual machine start-up. Heap storage for objects is reclaimed by an automatic storage management system (known as a garbage collector); objects are never explicitly deallocated. The Java Virtual Machine assumes no particular type of automatic storage management system, and the storage management technique may be chosen according to the implementor's system requirements. The heap may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger heap becomes unnecessary. The memory for the heap does not need to be contiguous.
+
+A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the heap, as well as, if the heap can be dynamically expanded or contracted, control over the maximum and minimum heap size.
+
+The following exceptional condition is associated with the heap:
+
+If a computation requires more heap than can be made available by the automatic storage management system, the Java Virtual Machine throws an OutOfMemoryError.
+
+2.5.4. Method Area
+
+The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.
+
+The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This version of the Java Virtual Machine specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous.
+
+A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the method area, as well as, in the case of a varying-size method area, control over the maximum and minimum method area size.
+
+The following exceptional condition is associated with the method area:
+
+If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.
+
+2.5.5. Run-Time Constant Pool
+
+A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.
+
+Each run-time constant pool is allocated from the Java Virtual Machine's method area (§2.5.4). The run-time constant pool for a class or interface is constructed when the class or interface is created (§5.3) by the Java Virtual Machine.
+
+The following exceptional condition is associated with the construction of the run-time constant pool for a class or interface:
+
+When creating a class or interface, if the construction of the run-time constant pool requires more memory than can be made available in the method area of the Java Virtual Machine, the Java Virtual Machine throws an OutOfMemoryError.
+
+See §5 (Loading, Linking, and Initializing) for information about the construction of the run-time constant pool.
+
+2.5.6. Native Method Stacks
+
+An implementation of the Java Virtual Machine may use conventional stacks, colloquially called "C stacks," to support native methods (methods written in a language other than the Java programming language). Native method stacks may also be used by the implementation of an interpreter for the Java Virtual Machine's instruction set in a language such as C. Java Virtual Machine implementations that cannot load native methods and that do not themselves rely on conventional stacks need not supply native method stacks. If supplied, native method stacks are typically allocated per thread when each thread is created.
+
+This specification permits native method stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the native method stacks are of a fixed size, the size of each native method stack may be chosen independently when that stack is created.
+
+A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the native method stacks, as well as, in the case of varying-size native method stacks, control over the maximum and minimum method stack sizes.
+
+The following exceptional conditions are associated with native method stacks:
+
+If the computation in a thread requires a larger native method stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
+
+If native method stacks can be dynamically expanded and native method stack expansion is attempted but insufficient memory can be made available, or if insufficient memory can be made available to create the initial native method stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
\ No newline at end of file
From 02ac2a97e5c8aac71b65471b18caa9384724f248 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 28 Aug 2014 18:46:33 +0800
Subject: [PATCH 007/524] Published with https://stackedit.io/
---
30.Java Runtime Data Areas.md | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/30.Java Runtime Data Areas.md b/30.Java Runtime Data Areas.md
index c085782..b363f53 100644
--- a/30.Java Runtime Data Areas.md
+++ b/30.Java Runtime Data Areas.md
@@ -1,5 +1,7 @@
#30.Java Runtime Data Areas.md
+
+
##30.1 运行时数据区(Runtime Data Areas)
Java虚拟机为程序的运行提供了各种不同的数据区,部分数据区与JVM的生命周期一致(随JVM启动而分配,JVM退出而释放),而另一部分则跟线程绑定,随着线程的启动和退出进行分配和释放。
@@ -18,6 +20,7 @@ Java虚拟的实现可以提供让程序员或用户来控制Java虚拟栈初始
* 如果线程需要的Java虚拟机栈大小超过限额,则抛出**StackOverflowError**。
* 如果Java虚拟机栈被设置为可动态拓展,当拓展时由于受限于物理内存的限制而无法实现拓展时,则抛出**OutOfMemoryError**。
+##30.1.2 堆(Heap)
2.5.3. Heap
@@ -31,6 +34,7 @@ The following exceptional condition is associated with the heap:
If a computation requires more heap than can be made available by the automatic storage management system, the Java Virtual Machine throws an OutOfMemoryError.
+## 方法区(Method Area)
2.5.4. Method Area
The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.
@@ -43,6 +47,8 @@ The following exceptional condition is associated with the method area:
If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.
+
+##运行时常量池(Runtime Constant Pool)
2.5.5. Run-Time Constant Pool
A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.
@@ -55,6 +61,7 @@ When creating a class or interface, if the construction of the run-time constant
See §5 (Loading, Linking, and Initializing) for information about the construction of the run-time constant pool.
+##本地方法栈(Native Method Stacks)
2.5.6. Native Method Stacks
An implementation of the Java Virtual Machine may use conventional stacks, colloquially called "C stacks," to support native methods (methods written in a language other than the Java programming language). Native method stacks may also be used by the implementation of an interpreter for the Java Virtual Machine's instruction set in a language such as C. Java Virtual Machine implementations that cannot load native methods and that do not themselves rely on conventional stacks need not supply native method stacks. If supplied, native method stacks are typically allocated per thread when each thread is created.
From 99db8d2b2769e54a1770b936f738da8d2f5a7642 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 28 Aug 2014 18:47:45 +0800
Subject: [PATCH 008/524] Published with https://stackedit.io/
---
30.Java Runtime Data Areas.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/30.Java Runtime Data Areas.md b/30.Java Runtime Data Areas.md
index b363f53..a0c712f 100644
--- a/30.Java Runtime Data Areas.md
+++ b/30.Java Runtime Data Areas.md
@@ -8,7 +8,7 @@ Java虚拟机为程序的运行提供了各种不同的数据区,部分数据
###30.1.1 程序计数器(Program Counter Rigister)
Java虚拟机支持多个线程在同一时刻运行。每一个Java虚拟机线程拥有自己的程序计数器。在任意时刻,任意线程都处于一个方法中(称为当前方法(current method)),如果是该方法是**非本地方法(not native method)**,则该程序计数器记录着**Java虚拟机执行的当前指令的地址**。而如果该方法为**本地方法(native method)**,则该程序计数器为undefined。
-##30.1.2 Java虚拟机栈(Java Virtual Machine Stacks)
+###30.1.2 Java虚拟机栈(Java Virtual Machine Stacks)
每个Java虚拟机线程都拥有各自的**Java虚拟机栈**,并与线程同时被创建。Java虚拟机栈用于存储**帧(frames)**。Java虚拟机栈跟传统语言的栈相似:存储局部变量、结果,同时参与方法的调用和返回。
Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.
@@ -20,7 +20,7 @@ Java虚拟的实现可以提供让程序员或用户来控制Java虚拟栈初始
* 如果线程需要的Java虚拟机栈大小超过限额,则抛出**StackOverflowError**。
* 如果Java虚拟机栈被设置为可动态拓展,当拓展时由于受限于物理内存的限制而无法实现拓展时,则抛出**OutOfMemoryError**。
-##30.1.2 堆(Heap)
+###30.1.2 堆(Heap)
2.5.3. Heap
@@ -34,7 +34,7 @@ The following exceptional condition is associated with the heap:
If a computation requires more heap than can be made available by the automatic storage management system, the Java Virtual Machine throws an OutOfMemoryError.
-## 方法区(Method Area)
+### 方法区(Method Area)
2.5.4. Method Area
The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.
@@ -48,7 +48,7 @@ The following exceptional condition is associated with the method area:
If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.
-##运行时常量池(Runtime Constant Pool)
+###运行时常量池(Runtime Constant Pool)
2.5.5. Run-Time Constant Pool
A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.
@@ -61,7 +61,7 @@ When creating a class or interface, if the construction of the run-time constant
See §5 (Loading, Linking, and Initializing) for information about the construction of the run-time constant pool.
-##本地方法栈(Native Method Stacks)
+###本地方法栈(Native Method Stacks)
2.5.6. Native Method Stacks
An implementation of the Java Virtual Machine may use conventional stacks, colloquially called "C stacks," to support native methods (methods written in a language other than the Java programming language). Native method stacks may also be used by the implementation of an interpreter for the Java Virtual Machine's instruction set in a language such as C. Java Virtual Machine implementations that cannot load native methods and that do not themselves rely on conventional stacks need not supply native method stacks. If supplied, native method stacks are typically allocated per thread when each thread is created.
From 0569f88309473905509d5eab37249db00966a4b4 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 28 Aug 2014 19:07:52 +0800
Subject: [PATCH 009/524] Published with https://stackedit.io/
---
30.Java Runtime Data Areas.md | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/30.Java Runtime Data Areas.md b/30.Java Runtime Data Areas.md
index a0c712f..ceed10d 100644
--- a/30.Java Runtime Data Areas.md
+++ b/30.Java Runtime Data Areas.md
@@ -3,12 +3,15 @@
##30.1 运行时数据区(Runtime Data Areas)
+
Java虚拟机为程序的运行提供了各种不同的数据区,部分数据区与JVM的生命周期一致(随JVM启动而分配,JVM退出而释放),而另一部分则跟线程绑定,随着线程的启动和退出进行分配和释放。
###30.1.1 程序计数器(Program Counter Rigister)
+
Java虚拟机支持多个线程在同一时刻运行。每一个Java虚拟机线程拥有自己的程序计数器。在任意时刻,任意线程都处于一个方法中(称为当前方法(current method)),如果是该方法是**非本地方法(not native method)**,则该程序计数器记录着**Java虚拟机执行的当前指令的地址**。而如果该方法为**本地方法(native method)**,则该程序计数器为undefined。
###30.1.2 Java虚拟机栈(Java Virtual Machine Stacks)
+
每个Java虚拟机线程都拥有各自的**Java虚拟机栈**,并与线程同时被创建。Java虚拟机栈用于存储**帧(frames)**。Java虚拟机栈跟传统语言的栈相似:存储局部变量、结果,同时参与方法的调用和返回。
Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.
@@ -22,17 +25,15 @@ Java虚拟的实现可以提供让程序员或用户来控制Java虚拟栈初始
###30.1.2 堆(Heap)
-2.5.3. Heap
-
-The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.
+Java虚拟机具有一个由所有Java虚拟机线程共享的一个堆。堆是**分配和储存所有的实例对象和数组的运行时数据区域**。
-The heap is created on virtual machine start-up. Heap storage for objects is reclaimed by an automatic storage management system (known as a garbage collector); objects are never explicitly deallocated. The Java Virtual Machine assumes no particular type of automatic storage management system, and the storage management technique may be chosen according to the implementor's system requirements. The heap may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger heap becomes unnecessary. The memory for the heap does not need to be contiguous.
+堆是在Java虚拟机启动时被创建的。堆的对象储存空间通过**自动存储管理系统(garbage collector简称gc)**进行回收,并不能像c/c++语言那样显示地进行释放。Java虚拟机没有指定限制使用的gc,这个可以由程序员和用户根据自己的情况来进行选择。堆可以是固定大小的,也可以通过计算来动态地拓展和收缩。同时,堆的内容空间地址不需要是连续的。
-A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the heap, as well as, if the heap can be dynamically expanded or contracted, control over the maximum and minimum heap size.
+Java虚拟机的实现可以提供让程序员和用户控制初始的堆大小,并且,可以让栈在最小值和最大值的限制范围内根据实际需要动态地拓展或收缩。
-The following exceptional condition is associated with the heap:
+以下异常情况与堆相关:
-If a computation requires more heap than can be made available by the automatic storage management system, the Java Virtual Machine throws an OutOfMemoryError.
+* 当堆需要拓展的内存大小大于自动存储管理系统所能提供的内存大小时,抛出**OutOfMemoryError**。
### 方法区(Method Area)
2.5.4. Method Area
From 8796b641e081ae7c57ea41a4e3e9dbe4f4af9211 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 28 Aug 2014 19:09:36 +0800
Subject: [PATCH 010/524] Published with https://stackedit.io/
---
30.Java Runtime Data Areas.md | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/30.Java Runtime Data Areas.md b/30.Java Runtime Data Areas.md
index ceed10d..041cecd 100644
--- a/30.Java Runtime Data Areas.md
+++ b/30.Java Runtime Data Areas.md
@@ -75,4 +75,10 @@ The following exceptional conditions are associated with native method stacks:
If the computation in a thread requires a larger native method stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
-If native method stacks can be dynamically expanded and native method stack expansion is attempted but insufficient memory can be made available, or if insufficient memory can be made available to create the initial native method stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
\ No newline at end of file
+If native method stacks can be dynamically expanded and native method stack expansion is attempted but insufficient memory can be made available, or if insufficient memory can be made available to create the initial native method stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
+
+### 拓展阅读
+
+* 翻译自:http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5
+* understanding-jvm-internals: http://www.cubrid.org/blog/dev-platform/understanding-jvm-internals/
+* understanding-java-garbage-collection: http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/
\ No newline at end of file
From c5df6bc185d4f1fca0b421344728cefe0c83eb1c Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 01:41:53 +0800
Subject: [PATCH 011/524] Published with https://stackedit.io/
---
30.Java Runtime Data Areas.md | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/30.Java Runtime Data Areas.md b/30.Java Runtime Data Areas.md
index 041cecd..79dae41 100644
--- a/30.Java Runtime Data Areas.md
+++ b/30.Java Runtime Data Areas.md
@@ -36,21 +36,17 @@ Java虚拟机的实现可以提供让程序员和用户控制初始的堆大小
* 当堆需要拓展的内存大小大于自动存储管理系统所能提供的内存大小时,抛出**OutOfMemoryError**。
### 方法区(Method Area)
-2.5.4. Method Area
-The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.
+Java虚拟机拥有一个由所有Java虚拟机线程共享的方法区。方法区类似于传统语言的用于存储编译代码的内存区域。(The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process. )它用于存储每个类的类结构,例如**运行时常量池(Runtime Constant Pool)**,字段和方法数据,以及方法和构造方法的代码,包括类、实例和接口在初始化时使用的特殊方法。
-The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This version of the Java Virtual Machine specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous.
+方法区也是在Java虚拟机启动时创建的。虽然方法区作为堆的一部分,但简单的Java虚拟机的实现可能不会对这部分区域进行gc操作和内存紧凑操作。Java虚拟机规范并不强制规范方法区的存储位置和管理已编译代码的策略。方法区可以是固定大小,也可以根据实际需要对方法区的大小进行拓展和紧凑操作。同时,方法区的内存不需要是连续的。
-A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the method area, as well as, in the case of a varying-size method area, control over the maximum and minimum method area size.
-
-The following exceptional condition is associated with the method area:
-
-If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.
+Java虚拟机的实现应该提供让程序员和用户控制初始的方法区内存大小,并且,可以让方法区在最小值和最大值的限制范围内根据实际需要动态地拓展或收缩。
+以下异常情况与方法区相关:
+* 如果方法区不能提供满足需要分配的内存时,Java虚拟机抛出**OutOfMemoryError**。
###运行时常量池(Runtime Constant Pool)
-2.5.5. Run-Time Constant Pool
A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.
From fe93825daf77b4da297e01161e1e8fed64902ee3 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 01:58:35 +0800
Subject: [PATCH 012/524] Published with https://stackedit.io/
---
30.Java Runtime Data Areas.md | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/30.Java Runtime Data Areas.md b/30.Java Runtime Data Areas.md
index 79dae41..de7e390 100644
--- a/30.Java Runtime Data Areas.md
+++ b/30.Java Runtime Data Areas.md
@@ -50,13 +50,11 @@ Java虚拟机的实现应该提供让程序员和用户控制初始的方法区
A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.
-Each run-time constant pool is allocated from the Java Virtual Machine's method area (§2.5.4). The run-time constant pool for a class or interface is constructed when the class or interface is created (§5.3) by the Java Virtual Machine.
+每个运行时常量池都是在Java虚拟机的方法区中进行分配的(也就是说运行时常量池是方法区中的一部分)。类/接口的运行时常量池在类/接口创建时被Java虚拟机构造。
-The following exceptional condition is associated with the construction of the run-time constant pool for a class or interface:
+以下异常情况与类/接口的运行时常量池的创建相关:
-When creating a class or interface, if the construction of the run-time constant pool requires more memory than can be made available in the method area of the Java Virtual Machine, the Java Virtual Machine throws an OutOfMemoryError.
-
-See §5 (Loading, Linking, and Initializing) for information about the construction of the run-time constant pool.
+当创建一个类或接口时,如果运行时常量池的创建需要更多的内存,而方法区没有足够的内存可以提供时,Java虚拟机抛出**OutOfMemoryError**。
###本地方法栈(Native Method Stacks)
2.5.6. Native Method Stacks
From a44c6df21af4c234aa8d526dccebea162dc7acc2 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 02:06:22 +0800
Subject: [PATCH 013/524] Published with https://stackedit.io/
---
30.Java Runtime Data Areas.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/30.Java Runtime Data Areas.md b/30.Java Runtime Data Areas.md
index de7e390..1c29030 100644
--- a/30.Java Runtime Data Areas.md
+++ b/30.Java Runtime Data Areas.md
@@ -47,8 +47,7 @@ Java虚拟机的实现应该提供让程序员和用户控制初始的方法区
* 如果方法区不能提供满足需要分配的内存时,Java虚拟机抛出**OutOfMemoryError**。
###运行时常量池(Runtime Constant Pool)
-
-A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.
+**运行时常量池**是一个类或接口的class文件的中**constant_pool**表的运行时表示。它包含多种常量:编译期的数值型字面量,运行时的方法和字段的引用。运行时常量池提供类似于一个传统的编程语言中的符号表的功能,但它比典型的符号表包含了更广泛的范围中的数据。
每个运行时常量池都是在Java虚拟机的方法区中进行分配的(也就是说运行时常量池是方法区中的一部分)。类/接口的运行时常量池在类/接口创建时被Java虚拟机构造。
From c6f6c3f367b6ea7b50ab9290ac918fabd2473518 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 02:13:28 +0800
Subject: [PATCH 014/524] Published with https://stackedit.io/
---
30.Java Runtime Data Areas.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/30.Java Runtime Data Areas.md b/30.Java Runtime Data Areas.md
index 1c29030..def7a3a 100644
--- a/30.Java Runtime Data Areas.md
+++ b/30.Java Runtime Data Areas.md
@@ -56,17 +56,17 @@ Java虚拟机的实现应该提供让程序员和用户控制初始的方法区
当创建一个类或接口时,如果运行时常量池的创建需要更多的内存,而方法区没有足够的内存可以提供时,Java虚拟机抛出**OutOfMemoryError**。
###本地方法栈(Native Method Stacks)
-2.5.6. Native Method Stacks
An implementation of the Java Virtual Machine may use conventional stacks, colloquially called "C stacks," to support native methods (methods written in a language other than the Java programming language). Native method stacks may also be used by the implementation of an interpreter for the Java Virtual Machine's instruction set in a language such as C. Java Virtual Machine implementations that cannot load native methods and that do not themselves rely on conventional stacks need not supply native method stacks. If supplied, native method stacks are typically allocated per thread when each thread is created.
This specification permits native method stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the native method stacks are of a fixed size, the size of each native method stack may be chosen independently when that stack is created.
-A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the native method stacks, as well as, in the case of varying-size native method stacks, control over the maximum and minimum method stack sizes.
-The following exceptional conditions are associated with native method stacks:
+Java虚拟机的实现应当提供这样的功能:程序员和用户可以控制本地方法栈的初始化大小,并且,可以让本地方法栈在最小值和最大值的限制范围内根据实际需要动态地拓展或收缩。
+
+以下异常情况与本地方法栈相关:
+* 如果本地方法栈需要更多的内存,但无法进行分配时,Java虚拟机抛出**StackOverflowError**。
-If the computation in a thread requires a larger native method stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
If native method stacks can be dynamically expanded and native method stack expansion is attempted but insufficient memory can be made available, or if insufficient memory can be made available to create the initial native method stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
From d4d30843af31186f1d9a195e8f65263bfaed3101 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 02:19:45 +0800
Subject: [PATCH 015/524] Published with https://stackedit.io/
---
30.Java Runtime Data Areas.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/30.Java Runtime Data Areas.md b/30.Java Runtime Data Areas.md
index def7a3a..ca4875d 100644
--- a/30.Java Runtime Data Areas.md
+++ b/30.Java Runtime Data Areas.md
@@ -56,8 +56,7 @@ Java虚拟机的实现应该提供让程序员和用户控制初始的方法区
当创建一个类或接口时,如果运行时常量池的创建需要更多的内存,而方法区没有足够的内存可以提供时,Java虚拟机抛出**OutOfMemoryError**。
###本地方法栈(Native Method Stacks)
-
-An implementation of the Java Virtual Machine may use conventional stacks, colloquially called "C stacks," to support native methods (methods written in a language other than the Java programming language). Native method stacks may also be used by the implementation of an interpreter for the Java Virtual Machine's instruction set in a language such as C. Java Virtual Machine implementations that cannot load native methods and that do not themselves rely on conventional stacks need not supply native method stacks. If supplied, native method stacks are typically allocated per thread when each thread is created.
+Java虚拟机应该使用传统的栈(通俗地将:C栈)来对**本地方法**(非Java实现的方法)进行支持。Native method stacks may also be used by the implementation of an interpreter for the Java Virtual Machine's instruction set in a language such as C. Java Virtual Machine implementations that cannot load native methods and that do not themselves rely on conventional stacks need not supply native method stacks. If supplied, native method stacks are typically allocated per thread when each thread is created.
This specification permits native method stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the native method stacks are of a fixed size, the size of each native method stack may be chosen independently when that stack is created.
From f3e876eba6533ade57c0f4a932cb484213a62425 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 11:48:25 +0800
Subject: [PATCH 016/524] Published with https://stackedit.io/
---
31.Understanding Java Garbage Collection.md | 53 +++++++++++++++++++++
1 file changed, 53 insertions(+)
create mode 100644 31.Understanding Java Garbage Collection.md
diff --git a/31.Understanding Java Garbage Collection.md b/31.Understanding Java Garbage Collection.md
new file mode 100644
index 0000000..0fdb2a1
--- /dev/null
+++ b/31.Understanding Java Garbage Collection.md
@@ -0,0 +1,53 @@
+#31.Understanding Java Garbage Collection.md
+理解GC(Garbage Collection)的工作原理对Java编程有什么益处呢?满足软件工程师的求知欲或许是一个不错的原因,但与此同时,也可以帮助你编写更加优秀的Java应用程序。
+
+这是我的个人的主观意见,但是我相信那些深谙GC的人往往更容易成为一个优秀的Java工程师。如果你对GC感兴趣,那么意味着你有不错的开发经验。如果你有过仔细选择合适的GC算法经验,这意味着你完全了解你开发应用程序的功能特点。当然,这也许只是优秀开发者的普遍衡量标准,然而我要说的是,要想成为一名优秀的开发者,理解GC是一门必修的课程。
+
+这篇文章的主要目的是以尽量简洁的方式向你讲解GC。我希望这篇文章能切切实实地对你有所帮助。回到正题,在GC中有个词汇**stop-the-word**,stop-the-word这个过程总会发生,无论你选择何种GC算法。stop-the-world意味着在**执行GC的过程中,JVM会中断所有的应用程序线程**( 除了GC需要的线程外)。被中断的线程会在GC完成后恢复。我们所关注的**GC调优就在于如何减少stop-the-world的运行时间**。
+
+## 垃圾收集器(Generational Garbage Collection)
+
+Java代码并不能显式地对内存进行分配和移除。有些人会将对象设置为null或者调用System.gc()方法来**显式**地移除内存空间。将对象设置为null没有大不了的,当调用System.gc()方法却会大大地响应系统的性能(我们并不需要这样做)。
+
+在Java中,开发者并不需要显式地在代码中释放内存,垃圾收集器会帮助我们找到不需要的对象并讲它们移除。垃圾收集器只所以被引入使用是基于以下两个假定前提:
+ 1. 大多数对象很快成为不可达状态;
+ 2. **老对象引用新对象**这种情况总是控制在很小的数量内。
+这两个假定前提被成为**弱世代假说(Weak generational hypothesis)**,基于这个假设,在HotSpot虚拟机中,内存(切确地说是Java Heap)被分为两种:**新生代(Young Generation)**与**老年代(Old Generation)**。
+
+新生代:绝大部分的新创建的对象都被分配到这里。由于大部分的对象很快会成为不可达状态,很多新创建的对象都分配到新生代,然后很快从这个区域被释放。对象从新生代被释放,我们称这个过程为**Minor GC**。
+
+老年代:当在新生代的对象没有成为不可达状态,并且从新生代存活下来后,我们会将这些对象复制到老年代。老年代的储存空间会比新生代的要大,所以在老年代发生GC的频率要远远低于在新生代的GC频率。对象从老年代被释放,我们称这个过程为**major GC**或**full GC**。
+
+我们看下以下两个图表:
+
+以上图中**永久代(Permanent Generation)**被成为**方法区**,它用于存储class文件和运行时常量池。所以,这里的存储空间并不用于“收留”从老年代存活下来的对象。当GC可能会在这个区域发生,我们也把在这个区域发生的GC算作full GC。
+
+有些人会有疑问:当老年代的对象需要引用新生代的对象,这时候会发生什么情况?
+
+为了处理这些情况,在老年代中会有个叫做**卡表(card table)**的东西,它是一个512字节的数据块。在老年代的对象需要引用新生代的对象时,会被记录到这里。然后,当新生代的GC执行时,这个**card table**会被检查以确定对象是否应该被GC处理,这样做可以防止对老年代的所有对象进行遍历。这个卡表使用一个被称为**写屏障**的装置进行管理,它可以让minor GC的性能更加高效,虽然它本身也需要一定的开销,但是整体的开销却是减少的。
+
+
+## 新生代(Composition of the Young Generation)
+
+为了深入理解GC,我们来看一下新生代。新生代被划分为3个区域空间:
+ * 一个伊甸园(One Eden Space)
+ * 两个幸存区 (Two Survivor spaces)
+ *
+There are 3 spaces in total, two of which are Survivor spaces. The order of execution process of each space is as below:
+The majority of newly created objects are located in the Eden space.
+After one GC in the Eden space, the surviving objects are moved to one of the Survivor spaces.
+After a GC in the Eden space, the objects are piled up into the Survivor space, where other surviving objects already exist.
+Once a Survivor space is full, surviving objects are moved to the other Survivor space. Then, the Survivor space that is full will be changed to a state where there is no data at all.
+The objects that survived these steps that have been repeated a number of times are moved to the old generation.
+As you can see by checking these steps, one of the Survivor spaces must remain empty. If data exists in both Survivor spaces, or the usage is 0 for both spaces, then take that as a sign that something is wrong with your system.
+The process of data piling up into the old generation through minor GCs can be shown as in the below chart:
+Figure 3: Before & After a GC.
+Figure 3: Before & After a GC.
+Note that in HotSpot VM, two techniques are used for faster memory allocations. One is called "bump-the-pointer," and the other is called "TLABs (Thread-Local Allocation Buffers)."
+Bump-the-pointer technique tracks the last object allocated to the Eden space. That object will be located on top of the Eden space. And if there is an object created afterwards, it checks only if the size of the object is suitable for the Eden space. If the said object seems right, it will be placed in the Eden space, and the new object goes on top. So, when new objects are created, only the lastly added object needs to be checked, which allows much faster memory allocations. However, it is a different story if we consider a multithreaded environment. To save objects used by multiple threads in the Eden space for Thread-Safe, an inevitable lock will occur and the performance will drop due to the lock-contention. TLABs is the solution to this problem in HotSpot VM. This allows each thread to have a small portion of its Eden space that corresponds to its own share. As each thread can only access to their own TLAB, even the bump-the-pointer technique will allow memory allocations without a lock.
+This has been a quick overview of the GC in the young generation. You do not necessarily have to remember the two techniques that I have just mentioned. You will not go to jail for not knowing them. But please remember that after the objects are first created in the Eden space, and the long-surviving objects are moved to the old generation through the Survivor space.
+
+
+
+## 参考文档
+* 翻译自:http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/
\ No newline at end of file
From 2376f1d821c55d9bff932d3c0d410d90eed92cc3 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 11:59:05 +0800
Subject: [PATCH 017/524] Published with https://stackedit.io/
---
31.Understanding Java Garbage Collection.md | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/31.Understanding Java Garbage Collection.md b/31.Understanding Java Garbage Collection.md
index 0fdb2a1..f460aa5 100644
--- a/31.Understanding Java Garbage Collection.md
+++ b/31.Understanding Java Garbage Collection.md
@@ -31,14 +31,13 @@ Java代码并不能显式地对内存进行分配和移除。有些人会将对
为了深入理解GC,我们来看一下新生代。新生代被划分为3个区域空间:
* 一个伊甸园(One Eden Space)
- * 两个幸存区 (Two Survivor spaces)
- *
-There are 3 spaces in total, two of which are Survivor spaces. The order of execution process of each space is as below:
-The majority of newly created objects are located in the Eden space.
-After one GC in the Eden space, the surviving objects are moved to one of the Survivor spaces.
-After a GC in the Eden space, the objects are piled up into the Survivor space, where other surviving objects already exist.
-Once a Survivor space is full, surviving objects are moved to the other Survivor space. Then, the Survivor space that is full will be changed to a state where there is no data at all.
-The objects that survived these steps that have been repeated a number of times are moved to the old generation.
+ * 两个幸存区 (Two Survivor Spaces)
+这三个区域空间中,有两个是幸存区(Survivor Spaces)。每个区域空间的执行过程如下:
+ 1. 绝大多数新创建的对象都首先被分配到伊甸园(Eden Space)。
+ 2. 当伊甸园的GC执行以后,存活下来的对象会被移动到其中一个幸存区(这个幸存区存放着之前存活下来的对象)。
+ 3. 一旦幸存区满了以后,该幸存区存活下来的对象会移动到另外一个幸存区,然后该幸存区会重置为空状态。
+ 4. 在多次幸存区的GC执行后而存活下来的对象会被移动到老年代。
+
As you can see by checking these steps, one of the Survivor spaces must remain empty. If data exists in both Survivor spaces, or the usage is 0 for both spaces, then take that as a sign that something is wrong with your system.
The process of data piling up into the old generation through minor GCs can be shown as in the below chart:
Figure 3: Before & After a GC.
From 4803623662a0e42b358caf7ac86c57ed6e90d8c9 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 12:01:07 +0800
Subject: [PATCH 018/524] Published with https://stackedit.io/
---
31.Understanding Java Garbage Collection.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/31.Understanding Java Garbage Collection.md b/31.Understanding Java Garbage Collection.md
index f460aa5..fe83e4b 100644
--- a/31.Understanding Java Garbage Collection.md
+++ b/31.Understanding Java Garbage Collection.md
@@ -30,9 +30,12 @@ Java代码并不能显式地对内存进行分配和移除。有些人会将对
## 新生代(Composition of the Young Generation)
为了深入理解GC,我们来看一下新生代。新生代被划分为3个区域空间:
+
* 一个伊甸园(One Eden Space)
* 两个幸存区 (Two Survivor Spaces)
+
这三个区域空间中,有两个是幸存区(Survivor Spaces)。每个区域空间的执行过程如下:
+
1. 绝大多数新创建的对象都首先被分配到伊甸园(Eden Space)。
2. 当伊甸园的GC执行以后,存活下来的对象会被移动到其中一个幸存区(这个幸存区存放着之前存活下来的对象)。
3. 一旦幸存区满了以后,该幸存区存活下来的对象会移动到另外一个幸存区,然后该幸存区会重置为空状态。
From 89fc55092a44293e8231e795fc6ad525ddd87100 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 12:01:51 +0800
Subject: [PATCH 019/524] Published with https://stackedit.io/
---
31.Understanding Java Garbage Collection.md | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/31.Understanding Java Garbage Collection.md b/31.Understanding Java Garbage Collection.md
index fe83e4b..3fe12d3 100644
--- a/31.Understanding Java Garbage Collection.md
+++ b/31.Understanding Java Garbage Collection.md
@@ -10,8 +10,10 @@
Java代码并不能显式地对内存进行分配和移除。有些人会将对象设置为null或者调用System.gc()方法来**显式**地移除内存空间。将对象设置为null没有大不了的,当调用System.gc()方法却会大大地响应系统的性能(我们并不需要这样做)。
在Java中,开发者并不需要显式地在代码中释放内存,垃圾收集器会帮助我们找到不需要的对象并讲它们移除。垃圾收集器只所以被引入使用是基于以下两个假定前提:
- 1. 大多数对象很快成为不可达状态;
- 2. **老对象引用新对象**这种情况总是控制在很小的数量内。
+
+1. 大多数对象很快成为不可达状态;
+2. **老对象引用新对象**这种情况总是控制在很小的数量内。
+
这两个假定前提被成为**弱世代假说(Weak generational hypothesis)**,基于这个假设,在HotSpot虚拟机中,内存(切确地说是Java Heap)被分为两种:**新生代(Young Generation)**与**老年代(Old Generation)**。
新生代:绝大部分的新创建的对象都被分配到这里。由于大部分的对象很快会成为不可达状态,很多新创建的对象都分配到新生代,然后很快从这个区域被释放。对象从新生代被释放,我们称这个过程为**Minor GC**。
@@ -31,15 +33,15 @@ Java代码并不能显式地对内存进行分配和移除。有些人会将对
为了深入理解GC,我们来看一下新生代。新生代被划分为3个区域空间:
- * 一个伊甸园(One Eden Space)
- * 两个幸存区 (Two Survivor Spaces)
+ * 一个伊甸园(One Eden Space)
+* 两个幸存区 (Two Survivor Spaces)
这三个区域空间中,有两个是幸存区(Survivor Spaces)。每个区域空间的执行过程如下:
- 1. 绝大多数新创建的对象都首先被分配到伊甸园(Eden Space)。
- 2. 当伊甸园的GC执行以后,存活下来的对象会被移动到其中一个幸存区(这个幸存区存放着之前存活下来的对象)。
- 3. 一旦幸存区满了以后,该幸存区存活下来的对象会移动到另外一个幸存区,然后该幸存区会重置为空状态。
- 4. 在多次幸存区的GC执行后而存活下来的对象会被移动到老年代。
+1. 绝大多数新创建的对象都首先被分配到伊甸园(Eden Space)。
+2. 当伊甸园的GC执行以后,存活下来的对象会被移动到其中一个幸存区(这个幸存区存放着之前存活下来的对象)。
+3. 一旦幸存区满了以后,该幸存区存活下来的对象会移动到另外一个幸存区,然后该幸存区会重置为空状态。
+4. 在多次幸存区的GC执行后而存活下来的对象会被移动到老年代。
As you can see by checking these steps, one of the Survivor spaces must remain empty. If data exists in both Survivor spaces, or the usage is 0 for both spaces, then take that as a sign that something is wrong with your system.
The process of data piling up into the old generation through minor GCs can be shown as in the below chart:
From 9eb37647245357b55582658645e13f73dad1fd23 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 12:02:40 +0800
Subject: [PATCH 020/524] Published with https://stackedit.io/
---
31.Understanding Java Garbage Collection.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/31.Understanding Java Garbage Collection.md b/31.Understanding Java Garbage Collection.md
index 3fe12d3..bbc27fd 100644
--- a/31.Understanding Java Garbage Collection.md
+++ b/31.Understanding Java Garbage Collection.md
@@ -21,12 +21,15 @@ Java代码并不能显式地对内存进行分配和移除。有些人会将对
老年代:当在新生代的对象没有成为不可达状态,并且从新生代存活下来后,我们会将这些对象复制到老年代。老年代的储存空间会比新生代的要大,所以在老年代发生GC的频率要远远低于在新生代的GC频率。对象从老年代被释放,我们称这个过程为**major GC**或**full GC**。
我们看下以下两个图表:
+
+
以上图中**永久代(Permanent Generation)**被成为**方法区**,它用于存储class文件和运行时常量池。所以,这里的存储空间并不用于“收留”从老年代存活下来的对象。当GC可能会在这个区域发生,我们也把在这个区域发生的GC算作full GC。
有些人会有疑问:当老年代的对象需要引用新生代的对象,这时候会发生什么情况?
为了处理这些情况,在老年代中会有个叫做**卡表(card table)**的东西,它是一个512字节的数据块。在老年代的对象需要引用新生代的对象时,会被记录到这里。然后,当新生代的GC执行时,这个**card table**会被检查以确定对象是否应该被GC处理,这样做可以防止对老年代的所有对象进行遍历。这个卡表使用一个被称为**写屏障**的装置进行管理,它可以让minor GC的性能更加高效,虽然它本身也需要一定的开销,但是整体的开销却是减少的。
+
## 新生代(Composition of the Young Generation)
From 75c4dba691dd62e2174588f25d4fbbb00084bfd6 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 12:03:24 +0800
Subject: [PATCH 021/524] Published with https://stackedit.io/
---
31.Understanding Java Garbage Collection.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/31.Understanding Java Garbage Collection.md b/31.Understanding Java Garbage Collection.md
index bbc27fd..5204ae0 100644
--- a/31.Understanding Java Garbage Collection.md
+++ b/31.Understanding Java Garbage Collection.md
@@ -36,8 +36,8 @@ Java代码并不能显式地对内存进行分配和移除。有些人会将对
为了深入理解GC,我们来看一下新生代。新生代被划分为3个区域空间:
- * 一个伊甸园(One Eden Space)
-* 两个幸存区 (Two Survivor Spaces)
+* 一个伊甸园(One Eden Space)
+* 两个幸存区 (Two Survivor Spaces)
这三个区域空间中,有两个是幸存区(Survivor Spaces)。每个区域空间的执行过程如下:
From 431fe3e0d0c9d961a106e7a43ea57c78c46b21c1 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 14:25:17 +0800
Subject: [PATCH 022/524] Published with https://stackedit.io/
---
31.Understanding Java Garbage Collection.md | 50 ++++++++++++++++++---
1 file changed, 44 insertions(+), 6 deletions(-)
diff --git a/31.Understanding Java Garbage Collection.md b/31.Understanding Java Garbage Collection.md
index 5204ae0..8ca0704 100644
--- a/31.Understanding Java Garbage Collection.md
+++ b/31.Understanding Java Garbage Collection.md
@@ -46,15 +46,53 @@ Java代码并不能显式地对内存进行分配和移除。有些人会将对
3. 一旦幸存区满了以后,该幸存区存活下来的对象会移动到另外一个幸存区,然后该幸存区会重置为空状态。
4. 在多次幸存区的GC执行后而存活下来的对象会被移动到老年代。
-As you can see by checking these steps, one of the Survivor spaces must remain empty. If data exists in both Survivor spaces, or the usage is 0 for both spaces, then take that as a sign that something is wrong with your system.
-The process of data piling up into the old generation through minor GCs can be shown as in the below chart:
-Figure 3: Before & After a GC.
-Figure 3: Before & After a GC.
-Note that in HotSpot VM, two techniques are used for faster memory allocations. One is called "bump-the-pointer," and the other is called "TLABs (Thread-Local Allocation Buffers)."
+在这个过程中,其中一个幸存区必须要保持为空状态。如果两个幸存区都是空状态或者都同时存在数据,你的系统一定出现了什么错误。
+
+数据通过minor GC并堆砌进入老年代的过程如下图所示:
+
+
+
+在HotSpot虚拟机中,有两项被用于快速分配内存的技术。一种被成为**bump-the-pointer**,而另一种是所谓的线程局部缓冲器TLABs (Thread-Local Allocation Buffers)。
+
Bump-the-pointer technique tracks the last object allocated to the Eden space. That object will be located on top of the Eden space. And if there is an object created afterwards, it checks only if the size of the object is suitable for the Eden space. If the said object seems right, it will be placed in the Eden space, and the new object goes on top. So, when new objects are created, only the lastly added object needs to be checked, which allows much faster memory allocations. However, it is a different story if we consider a multithreaded environment. To save objects used by multiple threads in the Eden space for Thread-Safe, an inevitable lock will occur and the performance will drop due to the lock-contention. TLABs is the solution to this problem in HotSpot VM. This allows each thread to have a small portion of its Eden space that corresponds to its own share. As each thread can only access to their own TLAB, even the bump-the-pointer technique will allow memory allocations without a lock.
-This has been a quick overview of the GC in the young generation. You do not necessarily have to remember the two techniques that I have just mentioned. You will not go to jail for not knowing them. But please remember that after the objects are first created in the Eden space, and the long-surviving objects are moved to the old generation through the Survivor space.
+你并不需要技术以上提到的两种技术。你需要记住的是:当对象创建之后会首先分配到伊甸园空间,然后通过在幸存区的长时间存活被晋升到老年代空间。
+
+##老年代的GC(GC for the Old Generation)
+
+老年代基本在空间被沾满时才执行GC操作。GC的执行过程根据GC的类型不同而有所差异,如果你对不同的GC类型有所了解,则会明白其中的差异所在。
+
+根据JDK7,共有5中GC类型:
+
+* Serial GC
+* Parallel GC
+* Parallel Old GC (Parrallel Compacting GC)
+* Concurrent Mark & Sweep GC (or CMS)
+* Garbage First GC (G1)
+
+其中,Serial GC不能应用于服务器上。这种GC通常在只有一个CPU内核的台式机器上才被创建
+其中,串行GC不能使用的操作的服务器上。这种类型的GC创建时有在台式计算机上只有一个CPU核心。使用该系列GC将显著删除应用程序的性能。 使用这种将很明显地降低应用程序的性能。
+
+现在让我们来了解没种GC的类型:
+
+###串行GC( Serial GC (-XX:+UseSerialGC))
+
+(The GC in the young generation uses the type we explained in the previous paragraph. ?)
+在老年代中我们使用一种称为**标记-清除-紧凑(mark-sweep-compact)**的算法。
+
+这种算法的第一步就是对老年代的幸存对象进行标记。然后,它从堆的从前往后逐个清理不需要的对象。最后对幸存的对象进行紧凑,使它们在位于连续的内存空间。这个过程会将堆分为两部分:一部分有数据,一部分没数据。Serial GC适用于小的内存空间和少量的CPU核心的机器。
+
+###并行GC (Parallel GC (-XX:+UseParallelGC))
+
+
+
+ 看上图,你可以清楚看到Serial GC与Parallel之间的差异。Serial GC仅使用一个线程去执行GC过程,而Parallel GC会使用多个线程去执行GC过程,因此,可得到更加优秀的性能。当机器拥有很大的内存和较多的CPU核心时,Paraller GC会表现得非常不错。Parallel GC也被称为**throughput GC**。
+
+###Parallel Old GC
+
+###Concurrent Mark & Sweep GC (or CMS)
+###Garbage First GC (G1)
## 参考文档
* 翻译自:http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/
\ No newline at end of file
From 9be2e2d4901b8f381408be13b166b0527e3b67e9 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 16:28:47 +0800
Subject: [PATCH 023/524] Published with https://stackedit.io/
---
31.Understanding Java Garbage Collection.md | 23 +++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/31.Understanding Java Garbage Collection.md b/31.Understanding Java Garbage Collection.md
index 8ca0704..caa8bd0 100644
--- a/31.Understanding Java Garbage Collection.md
+++ b/31.Understanding Java Garbage Collection.md
@@ -90,9 +90,32 @@ Bump-the-pointer technique tracks the last object allocated to the Eden space. T
###Parallel Old GC
+Parallel Old GC从JDK 5 update版本开始得到支持。相比Parallel GC,唯一的区别在于:Parallel Old GC只工作于老年代。它通过三个步骤进行工作:标记-总结-紧凑。The summary step identifies the surviving objects separately for the areas that the GC have previously performed, and thus different from the sweep step of the mark-sweep-compact algorithm. It goes through a little more complicated steps.
+
###Concurrent Mark & Sweep GC (or CMS)
+
+
+As you can see from the picture, the Concurrent Mark-Sweep GC is much more complicated than any other GC types that I have explained so far. The early initial mark step is simple. The surviving objects among the objects the closest to the classloader are searched. So, the pausing time is very short. In the concurrent mark step, the objects referenced by the surviving objects that have just been confirmed are tracked and checked. The difference of this step is that it proceeds while other threads are processed at the same time. In the remark step, the objects that were newly added or stopped being referenced in the concurrent mark step are checked. Lastly, in the concurrent sweep step, the garbage collection procedure takes place. The garbage collection is carried out while other threads are still being processed. Since this GC type is performed in this manner, the pausing time for GC is very short. The CMS GC is also called the low latency GC, and is used when the response time from all applications is crucial.
+While this GC type has the advantage of short stop-the-world time, it also has the following disadvantages.
+It uses more memory and CPU than other GC types.
+The compaction step is not provided by default.
+You need to carefully review before using this type. Also, if the compaction task needs to be carried out because of the many memory fragments, the stop-the-world time can be longer than any other GC types. You need to check how often and how long the compaction task is carried out.
+
###Garbage First GC (G1)
+
+
+
+Finally, let's learn about the garbage first (G1) GC.
+Figure 6: Layout of G1 GC.
+Figure 6: Layout of G1 GC.
+If you want to understand G1 GC, forget everything you know about the young generation and the old generation. As you can see in the picture, one object is allocated to each grid, and then a GC is executed. Then, once one area is full, the objects are allocated to another area, and then a GC is executed. The steps where the data moves from the three spaces of the young generation to the old generation cannot be found in this GC type. This type was created to replace the CMS GC, which has causes a lot of issues and complaints in the long term.
+The biggest advantage of the G1 GC is its performance. It is faster than any other GC types that we have discussed so far. But in JDK 6, this is called an early access and can be used only for a test. It is officially included in JDK 7. In my personal opinion, we need to go through a long test period (at least 1 year) before NHN can use JDK7 in actual services, so you probably should wait a while. Also, I heard a few times that a JVM crash occurred after applying the G1 in JDK 6. Please wait until it is more stable.
+I will talk about the GC tuning in the next issue, but I would like to ask you one thing in advance. If the size and the type of all objects created in the application are identical, all the GC options for WAS used in our company can be the same. But the size and the lifespan of the objects created by WAS vary depending on the service, and the type of equipment varies as well. In other words, just because a certain service uses the GC option "A," it does not mean that the same option will bring the best results for a different service. It is necessary to find the best values for the WAS threads, WAS instances for each equipment and each GC option by constant tuning and monitoring. This did not come from my personal experience, but from the discussion of the engineers making Oracle JVM for JavaOne 2010.
+In this issue, we have only glanced at the GC for Java. Please look forward to our next issue, where I will talk about how to monitor the Java GC status and tune GC.
+I would like to note that I referred to a new book released in December 2011 called "Java Performance" (Amazon, it can also be viewed from safari online, if the company provides an account), as well as “Memory Management in the Java HotSpotTM Virtual Machine,” a white paper provided by the Oracle website. (The book is different from "Java Performance Tuning.")
+By Sangmin Lee, Senior Engineer at Performance Engineering Lab, NHN Corporation.
+
## 参考文档
* 翻译自:http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/
\ No newline at end of file
From fd36cbc638772690286185e6cc5c1dcc158236d2 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 17:01:48 +0800
Subject: [PATCH 024/524] Published with https://stackedit.io/
---
31.Understanding Java Garbage Collection.md | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/31.Understanding Java Garbage Collection.md b/31.Understanding Java Garbage Collection.md
index caa8bd0..004d983 100644
--- a/31.Understanding Java Garbage Collection.md
+++ b/31.Understanding Java Garbage Collection.md
@@ -96,11 +96,15 @@ Parallel Old GC从JDK 5 update版本开始得到支持。相比Parallel GC,唯
-As you can see from the picture, the Concurrent Mark-Sweep GC is much more complicated than any other GC types that I have explained so far. The early initial mark step is simple. The surviving objects among the objects the closest to the classloader are searched. So, the pausing time is very short. In the concurrent mark step, the objects referenced by the surviving objects that have just been confirmed are tracked and checked. The difference of this step is that it proceeds while other threads are processed at the same time. In the remark step, the objects that were newly added or stopped being referenced in the concurrent mark step are checked. Lastly, in the concurrent sweep step, the garbage collection procedure takes place. The garbage collection is carried out while other threads are still being processed. Since this GC type is performed in this manner, the pausing time for GC is very short. The CMS GC is also called the low latency GC, and is used when the response time from all applications is crucial.
-While this GC type has the advantage of short stop-the-world time, it also has the following disadvantages.
-It uses more memory and CPU than other GC types.
-The compaction step is not provided by default.
-You need to carefully review before using this type. Also, if the compaction task needs to be carried out because of the many memory fragments, the stop-the-world time can be longer than any other GC types. You need to check how often and how long the compaction task is carried out.
+ 如你上图所看的,Concurrent Mark-Sweep GC比之前介绍的几种GC都要复杂得多。早期的**初始标记阶**段很简单,它的主要功能是最接近根类加载器的对象进行标记,这个阶段的停顿时间十分短暂。在**并发标记**阶段,对刚刚幸存下来的对象的引用进行跟踪和检查,这个过程中,其他的JVM线程不会被中止(也就是没有stop-the-world)。在**重新标记**阶段,会对**并发标记**阶段新添加或停止的引用进行确认。最后,在**并发清除**阶段,对不可达对象进行清理工作(也就GC动作),这个过程,其他的JVM线程也不会被中止。由于这种GC工作方式,GC的停顿时间非常短暂。CMS GC也被称为**低延迟GC**,这对那些对响应时间有严格要求的应用程序是至关重要的。
+
+虽然这种GC垃圾收集的停顿时间非常短暂,但是他对内存大小和CPU内核数量与性能有着更高的要求。
+虽然这种GC类型具有极其短暂的停顿时间,但它也有以下缺点:
+
+* 对内存和CPU的要求更加高。
+* 不提供默认的内存紧凑步骤
+
+在使用这种GC之前,你需要仔细地review。此外,在内存紧凑阶段,如果存在大量的内存碎片,那么这种GC需要停顿时间可能会比其他的GC类型的要长。你需要仔细检查内存紧凑发生的频率和时间。
###Garbage First GC (G1)
From ecd1c9cc59376a9548878ae6a3639906bfea7994 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Fri, 29 Aug 2014 17:24:36 +0800
Subject: [PATCH 025/524] Published with https://stackedit.io/
---
31.Understanding Java Garbage Collection.md | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/31.Understanding Java Garbage Collection.md b/31.Understanding Java Garbage Collection.md
index 004d983..6aecb19 100644
--- a/31.Understanding Java Garbage Collection.md
+++ b/31.Understanding Java Garbage Collection.md
@@ -108,18 +108,13 @@ Parallel Old GC从JDK 5 update版本开始得到支持。相比Parallel GC,唯
###Garbage First GC (G1)
-
-
-
-Finally, let's learn about the garbage first (G1) GC.
-Figure 6: Layout of G1 GC.
-Figure 6: Layout of G1 GC.
-If you want to understand G1 GC, forget everything you know about the young generation and the old generation. As you can see in the picture, one object is allocated to each grid, and then a GC is executed. Then, once one area is full, the objects are allocated to another area, and then a GC is executed. The steps where the data moves from the three spaces of the young generation to the old generation cannot be found in this GC type. This type was created to replace the CMS GC, which has causes a lot of issues and complaints in the long term.
-The biggest advantage of the G1 GC is its performance. It is faster than any other GC types that we have discussed so far. But in JDK 6, this is called an early access and can be used only for a test. It is officially included in JDK 7. In my personal opinion, we need to go through a long test period (at least 1 year) before NHN can use JDK7 in actual services, so you probably should wait a while. Also, I heard a few times that a JVM crash occurred after applying the G1 in JDK 6. Please wait until it is more stable.
-I will talk about the GC tuning in the next issue, but I would like to ask you one thing in advance. If the size and the type of all objects created in the application are identical, all the GC options for WAS used in our company can be the same. But the size and the lifespan of the objects created by WAS vary depending on the service, and the type of equipment varies as well. In other words, just because a certain service uses the GC option "A," it does not mean that the same option will bring the best results for a different service. It is necessary to find the best values for the WAS threads, WAS instances for each equipment and each GC option by constant tuning and monitoring. This did not come from my personal experience, but from the discussion of the engineers making Oracle JVM for JavaOne 2010.
-In this issue, we have only glanced at the GC for Java. Please look forward to our next issue, where I will talk about how to monitor the Java GC status and tune GC.
-I would like to note that I referred to a new book released in December 2011 called "Java Performance" (Amazon, it can also be viewed from safari online, if the company provides an account), as well as “Memory Management in the Java HotSpotTM Virtual Machine,” a white paper provided by the Oracle website. (The book is different from "Java Performance Tuning.")
-By Sangmin Lee, Senior Engineer at Performance Engineering Lab, NHN Corporation.
+最后,让我们来看下Garbage First GC(G1)
+
+
+
+如果你想要了解G1 GC,首先你要忘记关于新生代和老年代的一切知识点。Java堆(新生代&老年代)被划分为一个个大小固定的区域,对象被分派到这些区域中,如果一个区域被占满,则继续分配另外的区域,同时在后台维护一个优先列表,每次在允许的GC时间内,优先回收占用内存多的对象,这是就G1的来源。
+
+待续...
## 参考文档
* 翻译自:http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/
\ No newline at end of file
From e9973c98740ad66aa7c6af2a63dba2dfaac902dd Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 4 Sep 2014 09:05:54 +0800
Subject: [PATCH 026/524] Create 1.md
---
31.Java-NIO/1.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 31.Java-NIO/1.md
diff --git a/31.Java-NIO/1.md b/31.Java-NIO/1.md
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/31.Java-NIO/1.md
@@ -0,0 +1 @@
+test
From bb9f9078432ccfbe22dc3e7d4a9ba0f6a7a70ff2 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 4 Sep 2014 09:14:07 +0800
Subject: [PATCH 027/524] Delete 1.md
---
31.Java-NIO/1.md | 1 -
1 file changed, 1 deletion(-)
delete mode 100644 31.Java-NIO/1.md
diff --git a/31.Java-NIO/1.md b/31.Java-NIO/1.md
deleted file mode 100644
index 9daeafb..0000000
--- a/31.Java-NIO/1.md
+++ /dev/null
@@ -1 +0,0 @@
-test
From 47af7e22375ac228ec764c4b8826e78fb2b2b31f Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 4 Sep 2014 09:20:03 +0800
Subject: [PATCH 028/524] Create README.md
---
Java-NIO/README.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 Java-NIO/README.md
diff --git a/Java-NIO/README.md b/Java-NIO/README.md
new file mode 100644
index 0000000..2fc852e
--- /dev/null
+++ b/Java-NIO/README.md
@@ -0,0 +1 @@
+#Java NIO
From 3c0d15a69b3595fcfc54a70cf049c282aba31172 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 4 Sep 2014 09:21:03 +0800
Subject: [PATCH 029/524] Update README.md
---
Java-NIO/README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Java-NIO/README.md b/Java-NIO/README.md
index 2fc852e..13df960 100644
--- a/Java-NIO/README.md
+++ b/Java-NIO/README.md
@@ -1 +1,3 @@
#Java NIO
+
+翻译自:http://tutorials.jenkov.com/java-nio/index.html
From 0c6b76fb9a9b4ec4b841ebfae4739158512c5912 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 4 Sep 2014 10:14:58 +0800
Subject: [PATCH 030/524] Published with https://stackedit.io/
---
Java | 15 +++++++++++++++
1 file changed, 15 insertions(+)
create mode 100644 Java
diff --git a/Java b/Java
new file mode 100644
index 0000000..8f75dd7
--- /dev/null
+++ b/Java
@@ -0,0 +1,15 @@
+#01.Java NIO教程
+
+Java NIO(New IO)是一个可以替代标准IO的IO API,这意味着,它可以替代标准IO和Java Networking API。它提供了与标准IO不同的工作方式。
+
+##通道和缓冲区(Channels and Buffers)
+
+在标准IO接口中,操作的对象是**字节流**和**字符流**。而在NIO中,操作的对象则是**通道(Channels)**和**缓冲区(Buffers)**。数据总是从通道中读取到缓冲区,或从缓冲区写入到通道。
+
+##非阻塞IO(Non-blocking IO)
+
+Java NIO提供了非阻塞IO。举个例子,线程可以让通道读取数据到缓冲区中,当通道读取数据到缓冲区时,线程可以不必等待操作的完成,就可以去处理其他操作。从缓冲区写入到通道也类似。
+
+##选择器( Selectors)
+
+Java NIO引入了**选择器(Selectors)**的概念。一个选择器可以监听多个通道的时间(例如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。
From c3ecfd216a3fec1fdf2eced103f1a8aa95ac2fa0 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 4 Sep 2014 10:15:15 +0800
Subject: [PATCH 031/524] Published with https://stackedit.io/
From 53342702004478860a4d358c1eef59c97c466e2a Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 4 Sep 2014 10:15:47 +0800
Subject: [PATCH 032/524] Published with https://stackedit.io/
---
"Java-NIO/01.Java NIO\346\225\231\347\250\213.md" | 15 +++++++++++++++
1 file changed, 15 insertions(+)
create mode 100644 "Java-NIO/01.Java NIO\346\225\231\347\250\213.md"
diff --git "a/Java-NIO/01.Java NIO\346\225\231\347\250\213.md" "b/Java-NIO/01.Java NIO\346\225\231\347\250\213.md"
new file mode 100644
index 0000000..8f75dd7
--- /dev/null
+++ "b/Java-NIO/01.Java NIO\346\225\231\347\250\213.md"
@@ -0,0 +1,15 @@
+#01.Java NIO教程
+
+Java NIO(New IO)是一个可以替代标准IO的IO API,这意味着,它可以替代标准IO和Java Networking API。它提供了与标准IO不同的工作方式。
+
+##通道和缓冲区(Channels and Buffers)
+
+在标准IO接口中,操作的对象是**字节流**和**字符流**。而在NIO中,操作的对象则是**通道(Channels)**和**缓冲区(Buffers)**。数据总是从通道中读取到缓冲区,或从缓冲区写入到通道。
+
+##非阻塞IO(Non-blocking IO)
+
+Java NIO提供了非阻塞IO。举个例子,线程可以让通道读取数据到缓冲区中,当通道读取数据到缓冲区时,线程可以不必等待操作的完成,就可以去处理其他操作。从缓冲区写入到通道也类似。
+
+##选择器( Selectors)
+
+Java NIO引入了**选择器(Selectors)**的概念。一个选择器可以监听多个通道的时间(例如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。
From e71eadabae00a9f0f1a6fb52bccc00b7fc7f2d71 Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 4 Sep 2014 10:16:39 +0800
Subject: [PATCH 033/524] Delete Java
---
Java | 15 ---------------
1 file changed, 15 deletions(-)
delete mode 100644 Java
diff --git a/Java b/Java
deleted file mode 100644
index 8f75dd7..0000000
--- a/Java
+++ /dev/null
@@ -1,15 +0,0 @@
-#01.Java NIO教程
-
-Java NIO(New IO)是一个可以替代标准IO的IO API,这意味着,它可以替代标准IO和Java Networking API。它提供了与标准IO不同的工作方式。
-
-##通道和缓冲区(Channels and Buffers)
-
-在标准IO接口中,操作的对象是**字节流**和**字符流**。而在NIO中,操作的对象则是**通道(Channels)**和**缓冲区(Buffers)**。数据总是从通道中读取到缓冲区,或从缓冲区写入到通道。
-
-##非阻塞IO(Non-blocking IO)
-
-Java NIO提供了非阻塞IO。举个例子,线程可以让通道读取数据到缓冲区中,当通道读取数据到缓冲区时,线程可以不必等待操作的完成,就可以去处理其他操作。从缓冲区写入到通道也类似。
-
-##选择器( Selectors)
-
-Java NIO引入了**选择器(Selectors)**的概念。一个选择器可以监听多个通道的时间(例如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。
From 90defce24e491bc17ffdeb3d26dc843f2422e27f Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 4 Sep 2014 10:17:48 +0800
Subject: [PATCH 034/524] Published with https://stackedit.io/
---
.../02.Java NIO\346\246\202\350\247\210.md" | 47 +++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 "Java-NIO/02.Java NIO\346\246\202\350\247\210.md"
diff --git "a/Java-NIO/02.Java NIO\346\246\202\350\247\210.md" "b/Java-NIO/02.Java NIO\346\246\202\350\247\210.md"
new file mode 100644
index 0000000..2d460a4
--- /dev/null
+++ "b/Java-NIO/02.Java NIO\346\246\202\350\247\210.md"
@@ -0,0 +1,47 @@
+#02.Java NIO Overview
+
+Java NIO consist of the following core components:
+
+Channels
+Buffers
+Selectors
+Java NIO has more classes and components than these, but the Channel, Buffer and Selector forms the core of the API, in my opinion. The rest of the components, like Pipe and FileLock are merely utility classes to be used in conjunction with the three core components. Therefore, I'll focus on these three components in this NIO overview. The other components are explained in their own texts elsewhere in this tutorial. See the menu at the top corner of this page.
+
+Channels and Buffers
+
+Typically, all IO in NIO starts with a Channel. A Channel is a bit like a stream. From the Channel data can be read into a Buffer. Data can also be written from a Buffer into a Channel. Here is an illustration of that:
+
+Java NIO: Channels and Buffers
+Java NIO: Channels read data into Buffers, and Buffers write data into Channels
+There are several Channel and Buffer types. Here is a list of the primary Channel implementations in Java NIO:
+
+FileChannel
+DatagramChannel
+SocketChannel
+ServerSocketChannel
+As you can see, these channels cover UDP + TCP network IO, and file IO.
+
+There are a few interesting interfaces accompanying these classes too, but I'll keep them out of this Java NIO overview for simplicity's sake. They'll be explained where relevant, in other texts of this Java NIO tutorial.
+
+Here is a list of the core Buffer implementations in Java NIO:
+
+ByteBuffer
+CharBuffer
+DoubleBuffer
+FloatBuffer
+IntBuffer
+LongBuffer
+ShortBuffer
+These Buffer's cover the basic data types that you can send via IO: byte, short, int, long, float, double and characters.
+
+Java NIO also has a MappedByteBuffer which is used in conjunction with memory mapped files. I'll leave this Buffer out of this overview though.
+
+Selectors
+
+A Selector allows a single thread to handle multiple Channel's. This is handy if your application has many connections (Channels) open, but only has low traffic on each connection. For instance, in a chat server.
+
+Here is an illustration of a thread using a Selector to handle 3 Channel's:
+
+Java NIO: Selectors
+Java NIO: A Thread uses a Selector to handle 3 Channel's
+To use a Selector you register the Channel's with it. Then you call it's select() method. This method will block until there is an event ready for one of the registered channels. Once the method returns, the thread can then process these events. Examples of events are incoming connection, data received etc.
\ No newline at end of file
From 56b3fe6d294c75ff88812b51ac020a6b89fe5b5c Mon Sep 17 00:00:00 2001
From: cokepluscarbon <93948886@qq.com>
Date: Thu, 4 Sep 2014 10:33:56 +0800
Subject: [PATCH 035/524] add images
---
Java-NIO/images/overview-channels-buffers.png | Bin 0 -> 9174 bytes
Java-NIO/images/overview-selectors.png | Bin 0 -> 9016 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 Java-NIO/images/overview-channels-buffers.png
create mode 100644 Java-NIO/images/overview-selectors.png
diff --git a/Java-NIO/images/overview-channels-buffers.png b/Java-NIO/images/overview-channels-buffers.png
new file mode 100644
index 0000000000000000000000000000000000000000..ad738090f13531b8654184cd90e33258282f0dfd
GIT binary patch
literal 9174
zcmd6NcT^MI+wIV$BS`N8(wl%FT@aNbNar=u#7GmO^bU%O^dh}?>4=ih1H4F)-dlhu
z(jjz0CwK67`PRLE-n-U!*ZpIX$urNBnb~K~oW1usp-*%lQj)Qd0RTX$`RKj@0N{Ze
zuzU?4{A}yg>;}I`UqAZC6#%GyTyA&?!c?qaki<>%u?ERB5fLeupjnaA+TW0dncF>g
zH#?XMP+Zab2ne0<2$dgplnmO-blw{N)s^*J;s!>Z(FbLMm=du zu-V@GuowL!Lgt%TvkN|Wxjy=s$Dy5NroQ2wZe@uaKO+KgWPnwPykqOq@#!?jxM32< zbdT^@kdN^iqMtRY;UQy#ByifSgj=2U^{dx4#>}?W#hogzsz$qfFf3JyQ2RnQgPRiN zi7r6bn#nA@N#M#hgu@{4S2bo8^?T&oJ!=Ee?sHoAC&c>yg~DraFsdkTiXJ_Bm^AxO zh=9`Wmle^jnPw3UsLw9;ha;q1{-FERbQl3c*`*#7E5qylSSz_%D^*idX#d+~dnm5G zdeVxRZI}#~1oZS+^v&dtHWI*FqbR<2r~ALKATyKqRNK1q%gZ!eC@j2Rg1D8GnMXo3 zXmGLK67()ub8*c!b&(L# 2gPg`Y~qJ)C3mF3PA78 z?^gfuU82IIyLd(|KWlAV6trH7y=!(V(clEneH!^gb{;h?Tr#H0w$8MG&ePV@qi3KE z5e`&xRe(NdcE0Yh`ds`LaE)>o_quP(WjAmZxz!1JY*@=VC+FB-Qw`@K{Wlm>27cYW znCiOVHfsr!^2xHX`YR~q*1)}0Pcpd_vP?X}h!s@7-E6cSHK?q~0AG^YmaRpXju z`Q++2w0X9a%xgu7Z%yLpRMgM?c6L9gr?(|vVNqGBgr4(q#~7|BWoa6TvpP8A$-7II ze+=Q{US2syh}qu-$a);MCJH*SIl{xwM P9##+Y|=%&}LKbiXFet1B#A&&oO 0Qz_9B}xRJyQB-_XTPxgxc||=cFD7F-GjGF)6mDCA|%-F#EqTR%-5Dp z$}h+f-`h$zb$Hzd^tm=&9xKb{S3xG ufCcor?lPv1EB1W8RdOkQ59=Rs-{Pih9eoH- z+@$D+>ew8^aF@?Sep9qK@N#gds>zrmv%-(ZLtts4!R& ^sc~@1`a8i1O#n?lcf2CRHUtVfu7VoWGZyWTaeV;A$3M`43 zf^9Wbv_3Bp#Rn|xd~c`v!Qu88DJsXZKoHY8P<-g!H)w=5FkM24|0~1lF0NLpYwAi6 zr1<-8mCfILIgyp7!ky1|{;a-?^^qlm_}&1*fVeAf1qI`%a%j1!eoXak6SM805s@ zydw#X927bdnnC>7-B3fnB`CxkVP2CBt1T!MCCJv @;iH%IrR*j z5bc8|`JLfI@6nzc@J~psuxwqNhy&dVHM7;D!C-DI=sWGF`W>m9H0Cru$(zfq3oyAW z()#eaLzAARZMS#pWIS3*^9qYKS)t<7<>k8T^&lsmG4`bceT0KWMz^F e=&3JyMM z|E_ktM`0GOr_QTHFQtztqNqWqV)FMs* TuoHV->DGS3vg=IKZVDk8JkV9=! zdV`}EVXy_n|1ktY)dDjz=<4xRT0A_$3fHK~&P}V)ipR SzqsB?w_z~0EHUVyYx3aCs_o*=}qof*#|?;dq#>#BMueF z=X2eW;sH1Jg!+0dYCTx ~YI=UtrM+f;vI`XSMMC3f zIZ+R;{&^|6IR)O5fp|~tDfFh(u-4(}F)yELMY@uIRjuSBaIFP*#qVxdBj5W+`2P>r uT>P(2hrDPsFSt5|{&FqK|GwNK14j+nR3^XKwAKSA0Gb-Q_bb$_-u(}V58}1} literal 0 HcmV?d00001 diff --git a/Java-NIO/images/overview-selectors.png b/Java-NIO/images/overview-selectors.png new file mode 100644 index 0000000000000000000000000000000000000000..d5c075784a6fba1c33b50b585770468f75fe06db GIT binary patch literal 9016 zcmch7bySqw+xBoIB%~2(Bt?2akOmn*N>WNfx ^qlyV|#<7#Vd;|?k!>J SXI=4f;j18VX=I|Hyl|np=WU*CAWC-DI5|9W9;QLC3w&W&p#!>85S#?qCVZ z-yLQLhyW= 6Cw zWX#@(1H$VP_s?B0ESt-IjS3dK Gqp`QuTBrFqb1r+KJ6K98 zl8cNWIMQ#mPR|>1vL|VTqE}YXb!n 7Z-7fA*c49uU)USA(RzSeUo zd5+Y0dq8Zl^cpZ(n)fbPgO4Sd;8AP_(DyYYa Rk^X@BfsqWym4E<${D!QgSlr;nmP?Od6*0*r1u# zNEO;7r?;jLyD(cG@ElKnBn`upVIwePj=#f7N>*|^rh&2uAn~xP?Hz)Y0AGd;&;Lgj z?cXY0gifj4auNKxc7pegY#c7047RYciG*jrl=F2?C&FKBwV}+-=4F5I!<5JzcX;q* z1G_(ZE+8|7meBhnBiRQq 5n+UO3SD$OdH8;M^A~a zB%l0&l0cn|>JJ86;cC~5giK72r|T!{P4$qFp1Qt8@_uW;z(IrH;b(wFnU_?Q&WAZm zhZ{%hU1Cmw6Pr4$R3 ~( EdBiLi-u6JvFJkVmiKh+>oMqKrMIytZA4L#O{?x-&@U@ghm 0p6QWZ1MY7dm!N1{DAwvv%hrBfMh+33HuAF z5qF1zlss64_VgiED=_b0!fie8Xw2kp2IYzCen$#;I2&Pa*RLOYxo?1gY-JJr>t5ME z;<$Gxfv^+S_8tg3xiqi!fH?H}8QVX4Fg|d)xGyPx%SBuq1{NtrunMsyYeHU><(5Qv zR7ue{P2|J3kBKd24iAnQv&!QR%Hv!cJAdQ2wM( SUSEb5n~0ehyc5V zFPYbOc6yHcarJro_$6^-Gs(n+W!$;4fI2H*7w#zyWb%*Xv2RM;CuZ2)#`)jN8UG(y zN|k@F^_GkOT3#DhL}I+XI?y~Z?!VTb3{aYs3*ij^RvFIlIEu5uT426p)+}%4dq>(k zg%^?hjh!H0v}x;n(8Ld8q{amEV;{2vdu1SDx!+BSr81Cna#~#tBG$Mr7%?>T5v3|` zMnC5Da7GT9XT{y{Hprm1#`6fSZPI)lWc*}o{3IRhu@{-_OOzMzGbEVESubdPCt-Fu z)E5h9OM-TgiszU{cXd^jqOR`B)ClJVOg^q{ob=6FzSA8X9bFxIU%#BW515w^y9j!w zw4;(v@+%?);#FqaEeI2Dx!`7AmE2riNl2_0=JhC@Tft0SG;1bF-rTCm6*q{5O*;?& z5ep1xo@*_euWOyparT|(eCmx@B^r87O=V>vZ{hU#@>wgkN?oENX|r;A8;Q~Ri9!hO zU2toePy%lAWpR8({4QNqi1KgdX1N>OysSx+Dp8!jR+o3SbW*Iz`}CBcDF~Z{&ezY< z!!l s;E#UETpW>pMMI&mz%P zNB5-u38x_*Pph@m`szj)_Q;RD!W<1flY&S(DbrsPC+iZlE0-6`L{fnVxW+AlY?V-X zQ>VuP4e#4jlNePd(w9Hna-ro@VJy3ZA5G8Q-7OPhD{aGluVqS`5GFD*c{9h+V{TdN zUPy?oiVb(Wwc}%R`RE-fjlCMZHHN<4iF&MixkInz*(8; 8!f&Vm_G-S01KB$B;RR|?$WXGXDr)QkFRBE|goDT6; zXSN6u{ 9}MS@OI^QW#1U)it+?(mI}t3fjDLUXxH(>*w3?nO^oZhG7Uu z_SAqy4<3m4dyCC!`K-o&8u#i8vOTN|gi 2KCskYCX8U|H{S2a zAPZ8FFt>jt4{6(O@EMDBoGv4HAk{K9OIOo%Bm4#s{`7GF>fytkx(<_A6X{VcyC%hj zI|GjXZ`V6q#nlUL_eIb408`>F|21;m2QCz~s{( Uez2gX=#YRznD}$``){5G82O)t~l;qKgQMSfk)_pX>;MBILj?-EV7rm z67@DihPE5$URY#`5GbM?wI+B?y7KdEqP#9sc|OQ_5f =Rs7fw_Ml`ywZs7i}rO095qkR6ZU(Cz=6GBzZ`F^_=`1;1@GtK &`)~P1GZPJ9GmT^tvLn??~!U!#g+7(DcF%oY4d~Gqpu&xYzKA+dbmTMQ&W%3 zmf>GtBB?{LwSa1x1Xvo$klj7}-Ch+oKj>Q$n(-!B!}07))pfp6whYp>CZ8YxZz z{`jzj1WU4ZOq>~S*VoTUcP`oBZ7QV9W}2{pI+QXr$MzM_BXu$Wjp$QL=d2Ll@r2bl zzj5=5c=4R&XD|m7;C+uoJj$7b$NNSq1~O!nX0E9D4vCPxEK1ko@oqp#G2oTQ4o&<< zl2d$f>DQMY9ESKer&2OMG17@=L3Fr1U=EMCYgZrTDGOK`dq&4LtU7>85MEXkYY^CN zY{bljS5Z;=C6R(wgjQ_DSiuX24m(%{^IfBF!#NsZ)M${B&VXp}YN%;;XIbH8kmJ>B zd{jTV`96?reJd*%kK^GZmarwZOH^3040rXHq_zhnilkdJXg41ItfC4_Qhb~JoLooN zEqiR?oUxp6+AN!mT-m3z7P`Ebt|(1b5|60x>NAT4pdumh#=?pAT@_*KIp068w;!LL z^*lRCC0C|Vv#v4ZRfL#IT&ng;F{YFsTO`bTx-l^o^sSxZK*(00^Q+2GM_9+;wuoiB zEjbOz=!GretCmyD+kL^6i~cAupQFg8b@8<>HJilZnM@2WlV?xkBC`Twe00_FV&V#a z5ksIOIwt_xQ7qy=R1dcHn-QC5>7!3zRAfN~czZfbb*4KP|L{khI}UV6G&
#Wo%0)JJngrJ-{!;?sX O$uo-rfe~QhrI%#i=mSs8QpTbK9rEy}e`P!uG3y(rNEy(so1C`0e4!6#5 zXH%Rd?GOy(?AXI|ecrjZToi}?fLEFDSZ~j>C#whuIS|nC4PMd7gaT!n(s4iUN%L_b zEVT0nu2+MP_qxQ_sAqBCdYz9=8vI29`)5d+uS4cqF;*USK@L|c@bL&42seh9oxFp0 ztZ8HeJrM)?`oO*!K(B@JI63(e;d}{YB>P;|5=ke-_07+#F*Li`Ublqyd_bm~C9{AW zIA=z5pz&7g;@P+C?Y^MJX GXWJhNMRfnbkvd(zSNUU67$QXde(5&-Y(Q}^;1 zF`1j8=p*jq;UD1R;|*$4;{~huBd`U)qHMKp*3&e5MQAi?gk3G8K#;l;x>O;Qbhb8d zhCZ#Wuiunls^aVDzxoo9JN%Z9Spd&1go>7&cBrOw&RhfD9w7(3fSK;fSdjw*W~rrT zWI)rG9>3k(Oey;6@G*B7h?CSGs#<=k>#Z-ZaO;J1KR7>IJ0wue0Z#f>T&vguj~Fw& zym=ctv-&qP>~6XEwlo~KG^{C@0Gtm5?%Rh FP@`0KSmLlAQqSa0!%PCUZY#% <5tlg>byxm+lT5)P-KrcPqnuYJxo@?n@1X!^^_0^7=o z@6OLgKhF(d`L{JZ&s;ZF;5Lun5nISxIr8~=?$R!- fXlI@sc-DDlb0P^Fw9 zUwgW~Av`!n_;KyH<<#evl#vAGk@mV+H)poLsPmdnt7I6^buZ?*SIjfy_tZ7P_d_JD z{=ZyM;6NZ}qW9F2OHcGNWTj)MQsG8gQ6^%D#yt3*%LlcOz1vy6U$ah=cK6Hhu6_E9 zus(P4ChaB-5+!#0B9O6iU*%fAFXeuE1hG8vcX)*^>p_OHvgVgr*Y7pLqNB?jumTs4 z@&Cs!u+kQJ4XXVj02uDv`j_kjpJlEPxOZennP zUe>IBLjp?JHV(fOCIgE9a8JJIV>^%3xjP%gQLBc4R4?} >fXQWJBrVxH~;J|jnrwmIDf{;Ce<2i?=ayZ)sP)h zMA)2(mGcB |2vEm_~uFV5Nosx9! zF~c{WC;KnF2d)3m=DpaRqOA|fm)u_&bH28!*HMIEROo(3D-(>N?)qfha)HR5%CCT0 zd(a5tmD}6W@C4Pr{WSA?ImD`IV|zEdMMjJfp{I*NT^mcGotX|4m2i_94L)aQOj+6K z(s&4stQI-J?#t--u~nJ%1wj4?_(SJU^Ts3%JH0N~s|zo`>zk*}S2m+rd9^*)@;&h% zzohYSk{PR*VjBx7$`s7=Z`UhW4IlWS-?W^riPEDj=$`WO>Ewiro`vn;HSLDj%|n;Q z 5>G_`aUy6k` zXQ-d_+lh=eKCE7Ci~9JRjAu>; @WmemrkTM-m3r$b Z{*}?33_xN r-Q31qow=Rbmyr_up}xG}esAlDDYd?hEu@tdtPfCwt!*l-X~ZN~=SdES Gb~D-qf(TG8i@?vb%-TJGr25fn~MqapFx zO8kwZ@G%toJ&b|0*bv tEv5uiJrUhY0p2{3@8psHyz6ajFy z;$q%YvxMn*N`#ZXR(f@AAe_1KC|axOQO#~ROQ@8#*5rAYy5rdQ&!YA|I`FKk$Vf#` zp7s^?uuoHg)XZ6bC>c^HACtuY4sB=G(%F>@(>vacUP4@n_FPoL5H)3r-y3{S`na}y z@#yN@P_qTjfo>VLy4CWJtTm2~@wH#=01IG{Hg;eGT;??DlJ$OwQE_BzfI#jvpkGCi zk_rx%E6(TOq%neHA@1%C(*oz8Y%(xA+JFaq|2#Ld)Gc-#?m;gd#0!_QXZ?t=K-+kA zRPxKRP%(eGrYbr%`3{c`R6vRFJxe|trl~?8 z%bHRFE|c5Qur$OJTX7NZ;}@(-0ah(Nt2p%DFxBncg@C`e@r=Sp(P vKCdLf1cl z5oYx{b-W$y#%6V?Ino-DQy^${kdce3QC8l&<$_XK%UQfQLDk^ZJgW_(rSoOxk|(o6 zSy*Glr4&VeH9Zgxs>HvqXq>-P#^H$ohhfjgqosF|^uDJ1{98Rg+sTZtXNk-;8Ib1s zvZD@UhpjO@-R`eX%5qiH#H1nY_?**I-^Ne@f!Buao8jCv5!_ouMFB02zkT7Y_hAz? zkERW>rV4>Ti8v^N%7q|?GyO6;#jkt=mgsBNOnwgaO2ueidqaSS6M=p+;%-)Kc%MxU zXZD}Nbu{dyyd^x&mAg4>oFaop!OqPdWQZwWymaxJrfK>b1>=iUOU!I7E%wiuuY}7I z H!N^*`eOgmI)!#rUp)Cd4LN%?cROl{Mmp^8V zs$ms!hc4d)(?OvvpVJ2niyryW`y|FVXTVQfFIlcYugPx<-=Q~Q?x$VY-}{3 kFu4jv50p3a!)0|3d?XMSox> zgk{XwZ5`S7AVgbN6~fbG>WTcnMvbr&0MDyis|9KGQD`|PL^MPzDUg8TRZxlHT`g2p zh1}6008N&ffBw!nz1?H2+4F6ikpuSd0Y5Kf-mnJdpx#TiWNJfM^WJfj?GQWopVvSZ zNhTNhJ}uX-dw*tmx1|5{XH(X%2Kypkg+(JHIY|;9!j#R0K=uDv82`uE$!i(5iAL#8 zKLhJ_H8cHQ3*V&qg3Rjb3u~r>$n=ec5_LxyIk3tO@xj++-5a<2!n(?zr}XDRxKe|s zD~i!NvHq*G%9EFA4;#ZCK<~q=4wFBR>5Aj1qNq+-3j5>$-5fV(c99WE>BROO)OO0o zVFE7`d{OIbboX=S-g#>WnKI!8?0>S4mWe_Vk2!?|0~AbWoa%GOhYNt2TwOPS z1m3thQT?&dRksvG>7_OsWaJ)`Q+90k(pc0yZvIbV<44K2c5d4LlrTtG)@EdH(Pl)m zc23jEpW$v^rnxb8y`5GM|Ibz9C28kF+Pcd_ymg0U(+RU8g|op*z WM8Y@asdx6{VH)uA%$7!m}3W+ z%6YGUv)Y#20^)u)f;B!YL>vn %PrKJyn&|k)dtUBo+&p+GQ zYXM5bE9&n}VNsD7DNnnsm_+Ewa+COAdUzb-dmP>y-d-04j~RY%)YkT^Yr8<)Z~pTk zaOA4+SVqIq5vad_q*5b4!pO{|_0o1Ms@YKLKn=c_D&~Xf{>JqUJCn7rS3%PYcuRig zWS@~;5qlVaLD{ZS@~ED(F>;7^GHBC2r7
VOpGUO-Bo Hy$=3AfS}yZ literal 0 HcmV?d00001 From 3037890857b8f4f5e48317754b5763f0b8362373 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 10:43:48 +0800 Subject: [PATCH 036/524] Published with https://stackedit.io/ --- .../02.Java NIO\346\246\202\350\247\210.md" | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git "a/Java-NIO/02.Java NIO\346\246\202\350\247\210.md" "b/Java-NIO/02.Java NIO\346\246\202\350\247\210.md" index 2d460a4..bac97a1 100644 --- "a/Java-NIO/02.Java NIO\346\246\202\350\247\210.md" +++ "b/Java-NIO/02.Java NIO\346\246\202\350\247\210.md" @@ -1,42 +1,45 @@ -#02.Java NIO Overview +#02.Java NIO概览 -Java NIO consist of the following core components: +Java NIO包括以下核心组件: + + * 通道(Channels) + * 缓冲区(Buffers) + * 选择器(Selectors) -Channels -Buffers -Selectors -Java NIO has more classes and components than these, but the Channel, Buffer and Selector forms the core of the API, in my opinion. The rest of the components, like Pipe and FileLock are merely utility classes to be used in conjunction with the three core components. Therefore, I'll focus on these three components in this NIO overview. The other components are explained in their own texts elsewhere in this tutorial. See the menu at the top corner of this page. +Java NIO包含许多类和组件,但是**通道(Channels)**,**缓冲区(Buffers)**和**选择器(Selectors)**是其中最核心的接口。其他的组件,例如**管道(Pipe)**和文件锁**(FileLock)**只是为这三个核心组件服务的工具类。 -Channels and Buffers +##通道和缓冲区(Channels and Buffers) -Typically, all IO in NIO starts with a Channel. A Channel is a bit like a stream. From the Channel data can be read into a Buffer. Data can also be written from a Buffer into a Channel. Here is an illustration of that: +通常情况下,在NIO中的所有IO都起始于**通道(Channels)**。通道有点类似于**流**。来自通道的数据可以读取到缓冲区中,同样地,也可以从缓存区中写入数据到通道,如下图所示: -Java NIO: Channels and Buffers -Java NIO: Channels read data into Buffers, and Buffers write data into Channels -There are several Channel and Buffer types. Here is a list of the primary Channel implementations in Java NIO: + -FileChannel -DatagramChannel -SocketChannel -ServerSocketChannel -As you can see, these channels cover UDP + TCP network IO, and file IO. +Java NIO中有很多Channel和Buffer实现。以下是Java NIO中最主要的Channel的实现类; -There are a few interesting interfaces accompanying these classes too, but I'll keep them out of this Java NIO overview for simplicity's sake. They'll be explained where relevant, in other texts of this Java NIO tutorial. +* FileChannel +* DatagramChannel +* SocketChannel +* ServerSocketChannel -Here is a list of the core Buffer implementations in Java NIO: +正如你所见,这些通道覆盖了UDP、TCP和文件IO。 -ByteBuffer -CharBuffer -DoubleBuffer -FloatBuffer -IntBuffer -LongBuffer -ShortBuffer -These Buffer's cover the basic data types that you can send via IO: byte, short, int, long, float, double and characters. +以下是Java NIO中最主要的Buffer的实现类: + +* ByteBuffer +* CharBuffer +* ShortBuffer +* IntBuffer +* LongBuffer +* FloatBuffer +* DoubleBuffer + +以上的缓冲区实现类覆盖了你能通过IO发送的全部基本类型数据数据。Java NIO也提供了一个叫MappedByteBuffer的Buffer实现类,它用于跟内存映射文件交互。 + +##选择器(Selectors) -Java NIO also has a MappedByteBuffer which is used in conjunction with memory mapped files. I'll leave this Buffer out of this overview though. -Selectors A Selector allows a single thread to handle multiple Channel's. This is handy if your application has many connections (Channels) open, but only has low traffic on each connection. For instance, in a chat server. From c974507daaaec748d7463bdd3fa749db568b0e35 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 10:55:33 +0800 Subject: [PATCH 037/524] Published with https://stackedit.io/ --- .../02.Java NIO\346\246\202\350\247\210.md" | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git "a/Java-NIO/02.Java NIO\346\246\202\350\247\210.md" "b/Java-NIO/02.Java NIO\346\246\202\350\247\210.md" index bac97a1..27327bb 100644 --- "a/Java-NIO/02.Java NIO\346\246\202\350\247\210.md" +++ "b/Java-NIO/02.Java NIO\346\246\202\350\247\210.md" @@ -2,9 +2,9 @@ Java NIO包括以下核心组件: - * 通道(Channels) - * 缓冲区(Buffers) - * 选择器(Selectors) +* 通道(Channels) +* 缓冲区(Buffers) +* 选择器(Selectors) Java NIO包含许多类和组件,但是**通道(Channels)**,**缓冲区(Buffers)**和**选择器(Selectors)**是其中最核心的接口。其他的组件,例如**管道(Pipe)**和文件锁**(FileLock)**只是为这三个核心组件服务的工具类。 @@ -39,12 +39,12 @@ Java NIO中有很多Channel和Buffer实现。以下是Java NIO中最主要的Cha ##选择器(Selectors) +选择器允许使用一个线程来操作多个通道。这对于那些有大量网络连接但传输的数据量非常少的应用来说是非常方便有利的,例如聊天服务器。 +下面的示图描述了一个线程使用选择器来处理三个通道: -A Selector allows a single thread to handle multiple Channel's. This is handy if your application has many connections (Channels) open, but only has low traffic on each connection. For instance, in a chat server. - -Here is an illustration of a thread using a Selector to handle 3 Channel's: +
-Java NIO: Selectors -Java NIO: A Thread uses a Selector to handle 3 Channel's -To use a Selector you register the Channel's with it. Then you call it's select() method. This method will block until there is an event ready for one of the registered channels. Once the method returns, the thread can then process these events. Examples of events are incoming connection, data received etc. \ No newline at end of file +当你需要使用选择器时,你需要使用它向通道进行注册(register)。然后调用选择器的`select()`方法。这个方法会阻塞直至其中一个通道的事件就绪。一旦方法返回后,线程就可以对事件进行处理。这些事件包括:网路连接,接收数据等等。 \ No newline at end of file From 402839c60f6bcd427accaf74b93dd1e84218f74b Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 10:59:18 +0800 Subject: [PATCH 038/524] Published with https://stackedit.io/ --- .../03. Java NIO \351\200\232\351\201\223.md" | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 "Java-NIO/03. Java NIO \351\200\232\351\201\223.md" diff --git "a/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" "b/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" new file mode 100644 index 0000000..cb2267a --- /dev/null +++ "b/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" @@ -0,0 +1,54 @@ +#03. Java NIO 通道 + +Java NIO Channels are similar to streams with a few differences: + +You can both read and write to a Channels. Streams are typically one-way (read or write). +Channels can be read and written asynchronously. +Channels always read to, or write from, a Buffer. +As mentioned above, you read data from a channel into a buffer, and write data from a buffer into a channel. Here is an illustration of that: + +Java NIO: Channels and Buffers +Java NIO: Channels read data into Buffers, and Buffers write data into Channels +Channel Implementations + +Here are the most important Channel implementations in Java NIO: + +FileChannel +DatagramChannel +SocketChannel +ServerSocketChannel +The FileChannel reads data from and to files. + +The DatagramChannel can read and write data over the network via UDP. + +The SocketChannel can read and write data over the network via TCP. + +The ServerSocketChannel allows you to listen for incoming TCP connections, like a web server does. For each incoming connection a SocketChannel is created. + +Basic Channel Example + +Here is a basic example that uses a FileChannel to read some data into a Buffer: + +```Java +RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); +FileChannel inChannel = aFile.getChannel(); + +ByteBuffer buf = ByteBuffer.allocate(48); + +int bytesRead = inChannel.read(buf); +while (bytesRead != -1) { + + System.out.println("Read " + bytesRead); + buf.flip(); + + while(buf.hasRemaining()){ + System.out.print((char) buf.get()); + } + + buf.clear(); + bytesRead = inChannel.read(buf); +} +aFile.close(); +``` + +Notice the buf.flip() call. First you read into a Buffer. Then you flip it. Then you read out of it. I'll get into more detail about that in the next text about Buffer's. \ No newline at end of file From 5840f1dc21d4d5a95a5cf5df8782844d02d4358c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 11:10:10 +0800 Subject: [PATCH 039/524] Published with https://stackedit.io/ --- "Java-NIO/03. Java NIO \351\200\232\351\201\223.md" | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git "a/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" "b/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" index cb2267a..c0831f3 100644 --- "a/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" +++ "b/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" @@ -1,5 +1,15 @@ #03. Java NIO 通道 +Java NIO的通道(Channels)类似与标准IO中的**流(Stream)**,它们之间的区别在于: + +* 你可以从管道中读取或写入数据(双向),但是流只能是读取或写入(单向)。 +* 通道可以进行异步(Asynchonously)操作。 +* 通道(Channel)总是从缓冲区(Buffers)中读取或写入数据。 + +如上面所提到的,数据总是从管道中读取到缓冲区,后从缓冲区中写入到通道。如下图所示: + + + Java NIO Channels are similar to streams with a few differences: You can both read and write to a Channels. Streams are typically one-way (read or write). From 572f4d4fb9a0f9216466e1e7d0e562b2583ad8bb Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 11:19:16 +0800 Subject: [PATCH 040/524] Published with https://stackedit.io/ --- .../03. Java NIO \351\200\232\351\201\223.md" | 38 +++++-------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git "a/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" "b/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" index c0831f3..30b4e53 100644 --- "a/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" +++ "b/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" @@ -1,6 +1,6 @@ #03. Java NIO 通道 -Java NIO的通道(Channels)类似与标准IO中的**流(Stream)**,它们之间的区别在于: +Java NIO的**通道(Channels)**类似与标准IO中的**流(Stream)**,它们之间的区别在于: * 你可以从管道中读取或写入数据(双向),但是流只能是读取或写入(单向)。 * 通道可以进行异步(Asynchonously)操作。 @@ -10,34 +10,16 @@ Java NIO的通道(Channels)类似与标准IO中的**流(Stream)**,它  -Java NIO Channels are similar to streams with a few differences: + 以下是Java NIO中Chanel的最重要的实现类: -You can both read and write to a Channels. Streams are typically one-way (read or write). -Channels can be read and written asynchronously. -Channels always read to, or write from, a Buffer. -As mentioned above, you read data from a channel into a buffer, and write data from a buffer into a channel. Here is an illustration of that: +* FileChannel:从文件中读取或写入数据 +* DatagramChannel:从UPD中读取或写入数据 +* SocketChannel:从TCP中读取或写入数据 +* ServerSocketChannel:用于监听TCP连接,每接收一个连接就创建一个`SocketChannel` -Java NIO: Channels and Buffers -Java NIO: Channels read data into Buffers, and Buffers write data into Channels -Channel Implementations +##Channel例子(Basic Channel Example) -Here are the most important Channel implementations in Java NIO: - -FileChannel -DatagramChannel -SocketChannel -ServerSocketChannel -The FileChannel reads data from and to files. - -The DatagramChannel can read and write data over the network via UDP. - -The SocketChannel can read and write data over the network via TCP. - -The ServerSocketChannel allows you to listen for incoming TCP connections, like a web server does. For each incoming connection a SocketChannel is created. - -Basic Channel Example - -Here is a basic example that uses a FileChannel to read some data into a Buffer: +以下的代码示例演示了从FileChannel读取数据到Buffer中: ```Java RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); @@ -60,5 +42,5 @@ while (bytesRead != -1) { } aFile.close(); ``` - -Notice the buf.flip() call. First you read into a Buffer. Then you flip it. Then you read out of it. I'll get into more detail about that in the next text about Buffer's. \ No newline at end of file + +注意`buf.flip`的调用。当你写入数据到Buffer后,需要调用这个方法,然后才能从Buffer中读取数据。 \ No newline at end of file From c92e426cbe7bfa35b9c050e76b2ee6848ad432da Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 11:19:56 +0800 Subject: [PATCH 041/524] =?UTF-8?q?Rename=2003.=20Java=20NIO=20=E9=80=9A?= =?UTF-8?q?=E9=81=93.md=20to=2003.=20Java=20NIO=E9=80=9A=E9=81=93.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../03. Java NIO\351\200\232\351\201\223.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename "Java-NIO/03. Java NIO \351\200\232\351\201\223.md" => "Java-NIO/03. Java NIO\351\200\232\351\201\223.md" (96%) diff --git "a/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" "b/Java-NIO/03. Java NIO\351\200\232\351\201\223.md" similarity index 96% rename from "Java-NIO/03. Java NIO \351\200\232\351\201\223.md" rename to "Java-NIO/03. Java NIO\351\200\232\351\201\223.md" index 30b4e53..90f6b20 100644 --- "a/Java-NIO/03. Java NIO \351\200\232\351\201\223.md" +++ "b/Java-NIO/03. Java NIO\351\200\232\351\201\223.md" @@ -43,4 +43,4 @@ while (bytesRead != -1) { aFile.close(); ``` -注意`buf.flip`的调用。当你写入数据到Buffer后,需要调用这个方法,然后才能从Buffer中读取数据。 \ No newline at end of file +注意`buf.flip`的调用。当你写入数据到Buffer后,需要调用这个方法,然后才能从Buffer中读取数据。 From e6afa2995e762ccf507214b5dee394d445389325 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 11:20:37 +0800 Subject: [PATCH 042/524] =?UTF-8?q?Update=2003.=20Java=20NIO=E9=80=9A?= =?UTF-8?q?=E9=81=93.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "Java-NIO/03. Java NIO\351\200\232\351\201\223.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-NIO/03. Java NIO\351\200\232\351\201\223.md" "b/Java-NIO/03. Java NIO\351\200\232\351\201\223.md" index 90f6b20..291e3f3 100644 --- "a/Java-NIO/03. Java NIO\351\200\232\351\201\223.md" +++ "b/Java-NIO/03. Java NIO\351\200\232\351\201\223.md" @@ -1,4 +1,4 @@ -#03. Java NIO 通道 +#03. Java NIO通道 Java NIO的**通道(Channels)**类似与标准IO中的**流(Stream)**,它们之间的区别在于: From 17172a3704285181ebb43546efd694fa841b05d6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 11:20:53 +0800 Subject: [PATCH 043/524] =?UTF-8?q?Rename=2003.=20Java=20NIO=E9=80=9A?= =?UTF-8?q?=E9=81=93.md=20to=2003.Java=20NIO=E9=80=9A=E9=81=93.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../03.Java NIO\351\200\232\351\201\223.md" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "Java-NIO/03. Java NIO\351\200\232\351\201\223.md" => "Java-NIO/03.Java NIO\351\200\232\351\201\223.md" (100%) diff --git "a/Java-NIO/03. Java NIO\351\200\232\351\201\223.md" "b/Java-NIO/03.Java NIO\351\200\232\351\201\223.md" similarity index 100% rename from "Java-NIO/03. Java NIO\351\200\232\351\201\223.md" rename to "Java-NIO/03.Java NIO\351\200\232\351\201\223.md" From e3be549e221c8ca5ecdf3eb8873f5ce54aca2f4a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 11:22:31 +0800 Subject: [PATCH 044/524] Published with https://stackedit.io/ --- ...IO\347\274\223\345\206\262\345\214\272.md" | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 "Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" new file mode 100644 index 0000000..c7bd206 --- /dev/null +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -0,0 +1,173 @@ +#04.Java NIO Buffer + +Java NIO Buffers are used when interacting with NIO Channels. As you know, data is read from channels into buffers, and written from buffers into channels. + +A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory block is wrapped in a NIO Buffer object, which provides a set of methods that makes it easier to work with the memory block. + +Basic Buffer Usage + +Using a Buffer to read and write data typically follows this little 4-step process: + +Write data into the Buffer +Call buffer.flip() +Read data out of the Buffer +Call buffer.clear() or buffer.compact() +When you write data into a buffer, the buffer keeps track of how much data you have written. Once you need to read the data, you need to switch the buffer from writing mode into reading mode using the flip() method call. In reading mode the buffer lets you read all the data written into the buffer. + +Once you have read all the data, you need to clear the buffer, to make it ready for writing again. You can do this in two ways: By calling clear() or by calling compact(). The clear() method clears the whole buffer. The compact() method only clears the data which you have already read. Any unread data is moved to the beginning of the buffer, and data will now be written into the buffer after the unread data. + +Here is a simple Buffer usage example, with the write, flip, read and clear operations maked in bold: + +RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); +FileChannel inChannel = aFile.getChannel(); + +//create buffer with capacity of 48 bytes +ByteBuffer buf = ByteBuffer.allocate(48); + +int bytesRead = inChannel.read(buf); //read into buffer. +while (bytesRead != -1) { + + buf.flip(); //make buffer ready for read + + while(buf.hasRemaining()){ + System.out.print((char) buf.get()); // read 1 byte at a time + } + + buf.clear(); //make buffer ready for writing + bytesRead = inChannel.read(buf); +} +aFile.close(); +Buffer Capacity, Position and Limit + +A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory block is wrapped in a NIO Buffer object, which provides a set of methods that makes it easier to work with the memory block. + +A Buffer has three properties you need to be familiar with, in order to understand how a Buffer works. These are: + +capacity +position +limit +The meaning of position and limit depends on whether the Buffer is in read or write mode. Capacity always means the same, no matter the buffer mode. + +Here is an illustration of capacity, position and limit in write and read modes. The explanation follows in the sections after the illustration. + +Java NIO: Buffer capacity, position and limit in write and read mode. +Buffer capacity, position and limit in write and read mode. +Capacity + +Being a memory block, a Buffer has a certain fixed size, also called its "capacity". You can only write capacity bytes, longs, chars etc. into the Buffer. Once the Buffer is full, you need to empty it (read the data, or clear it) before you can write more data into it. + +Position + +When you write data into the Buffer, you do so at a certain position. Initially the position is 0. When a byte, long etc. has been written into the Buffer the position is advanced to point to the next cell in the buffer to insert data into. Position can maximally become capacity - 1. + +When you read data from a Buffer you also do so from a given position. When you flip a Buffer from writing mode to reading mode, the position is reset back to 0. As you read data from the Buffer you do so from position, and position is advanced to next position to read. + +Limit + +In write mode the limit of a Buffer is the limit of how much data you can write into the buffer. In write mode the limit is equal to the capacity of the Buffer. + +When flipping the Buffer into read mode, limit means the limit of how much data you can read from the data. Therefore, when flipping a Buffer into read mode, limit is set to write position of the write mode. In other words, you can read as many bytes as were written (limit is set to the number of bytes written, which is marked by position). + +Buffer Types + +Java NIO comes with the following Buffer types: + +ByteBuffer +MappedByteBuffer +CharBuffer +DoubleBuffer +FloatBuffer +IntBuffer +LongBuffer +ShortBuffer +As you can see, these Buffer types represent different data types. In other words, they let you work with the bytes in the buffer as char, short, int, long, float or double instead. + +The MappedByteBuffer is a bit special, and will be covered in its own text. + +Allocating a Buffer + +To obtain a Buffer object you must first allocate it. Every Buffer class has an allocate() method that does this. Here is an example showing the allocation of a ByteBuffer, with a capacity of 48 bytes: + +ByteBuffer buf = ByteBuffer.allocate(48); +Here is an example allocating a CharBuffer with space for 1024 characters: + +CharBuffer buf = CharBuffer.allocate(1024); +Writing Data to a Buffer + +You can write data into a Buffer in two ways: + +Write data from a Channel into a Buffer +Write data into the Buffer yourself, via the buffer's put() methods. +Here is an example showing how a Channel can write data into a Buffer: + +int bytesRead = inChannel.read(buf); //read into buffer. +Here is an example that writes data into a Buffer via the put() method: + +buf.put(127); +There are many other versions of the put() method, allowing you to write data into the Buffer in many different ways. For instance, writing at specific positions, or writing an array of bytes into the buffer. See the JavaDoc for the concrete buffer implementation for more details. + +flip() + +The flip() method switches a Buffer from writing mode to reading mode. Calling flip() sets the position back to 0, and sets the limit to where position just was. + +In other words, position now marks the reading position, and limit marks how many bytes, chars etc. were written into the buffer - the limit of how many bytes, chars etc. that can be read. + +Reading Data from a Buffer + +There are two ways you can read data from a Buffer. + +Read data from the buffer into a channel. +Read data from the buffer yourself, using one of the get() methods. +Here is an example of how you can read data from a buffer into a channel: + +//read from buffer into channel. +int bytesWritten = inChannel.write(buf); +Here is an example that reads data from a Buffer using the get() method: + +byte aByte = buf.get(); +There are many other versions of the get() method, allowing you to read data from the Buffer in many different ways. For instance, reading at specific positions, or reading an array of bytes from the buffer. See the JavaDoc for the concrete buffer implementation for more details. + +rewind() + +The Buffer.rewind() sets the position back to 0, so you can reread all the data in the buffer. The limit remains untouched, thus still marking how many elements (bytes, chars etc.) that can be read from the Buffer. + +clear() and compact() + +Once you are done reading data out of the Buffer you have to make the Buffer ready for writing again. You can do so either by calling clear() or by calling compact(). + +If you call clear() the position is set back to 0 and the limit to capacity. In other words, the Buffer is cleared. The data in the Buffer is not cleared. Only the markers telling where you can write data into the Buffer are. + +If there is any unread data in the Buffer when you call clear() that data will be "forgotten", meaning you no longer have any markers telling what data has been read, and what has not been read. + +If there is still unread data in the Buffer, and you want to read it later, but you need to do some writing first, call compact() instead of clear(). + +compact() copies all unread data to the beginning of the Buffer. Then it sets position to right after the last unread element. The limit property is still set to capacity, just like clear() does. Now the Buffer is ready for writing, but you will not overwrite the unread data. + +mark() and reset() + +You can mark a given position in a Buffer by calling the Buffer.mark() method. You can then later reset the position back to the marked position by calling the Buffer.reset() method. Here is an example: + +buffer.mark(); + +//call buffer.get() a couple of times, e.g. during parsing. + +buffer.reset(); //set position back to mark. +equals() and compareTo() + +It is possible to compare two buffers using equals() and compareTo(). + +equals() + +Two buffers are equal if: + +They are of the same type (byte, char, int etc.) +They have the same amount of remaining bytes, chars etc. in the buffer. +All remaining bytes, chars etc. are equal. +As you can see, equals only compares part of the Buffer, not every single element inside it. In fact, it just compares the remaining elements in the Buffer. + +compareTo() + +The compareTo() method compares the remaining elements (bytes, chars etc.) of the two buffers, for use in e.g. sorting routines. A buffer is considered "smaller" than another buffer if: + +The first element which is equal to the corresponding element in the other buffer, is smaller than that in the other buffer. +All elements are equal, but the first buffer runs out of elements before the second buffer does (it has fewer elements). \ No newline at end of file From 31a086952f5344caf49e811d427ba01356d6c946 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 11:22:53 +0800 Subject: [PATCH 045/524] Published with https://stackedit.io/ --- "Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index c7bd206..71582be 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -1,4 +1,4 @@ -#04.Java NIO Buffer +#04.Java NIO缓冲区 Java NIO Buffers are used when interacting with NIO Channels. As you know, data is read from channels into buffers, and written from buffers into channels. From aa8d8cfdc0848e1ee9f5e5af6c86f10d0b027438 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 11:22:31 +0800 Subject: [PATCH 046/524] add images --- Java-NIO/images/buffers-modes.png | Bin 0 -> 16208 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Java-NIO/images/buffers-modes.png diff --git a/Java-NIO/images/buffers-modes.png b/Java-NIO/images/buffers-modes.png new file mode 100644 index 0000000000000000000000000000000000000000..15a094ab4a75da555304a8d2e78f1d91fffeb447 GIT binary patch literal 16208 zcmb8WWmHwq`v-bxkOn0r1?dI>={g8VcXxLlx=}(9RJx_RyGv5K>k!i2U3c^SUH&ic zTKC0XXPswe@0s~L{me|5f}8~UtGBN}AP~BgBv=Uqg1H4AHDp+Tf>F>H4*Z}vNNPF* z|NcBbFtH36L;w-VMM_p2X#oZwg^j8Qb^G^!BykNF5r~V0y%VUQbWjo?p}7Dgu&J}L zlcj@;rM(>p7v&u#K!5d27qfTpaI!SFZ~+x#4)Ow2jQ^-kriRa5$z3dMO+lPjm?%IC z%5#gdy_t)fp_3^{*Wu~8JL-QQw{$kPF$B6gf$G|;qX07UGg;lx$
8G4Pa{;^sB>3Xl{D}{UzivT9bw>6$jNu>rs$2{Xy3iruWLPC(3gH=Q`1^JsTEQ3 zfXDP%+os6WISduA3GfM-i6o3%sZdaxf!&CG_Tj%`LHMIhpUTbNZb}+a>}x$JxI5 zaLU;rhq+52ITkRVCBjSy0`Qv;GbsQ9!NV(Dfk0ST!caJnurLUM3C!>Re?vg-uJ1A~ zuLOUE{V`$U`23L~Rt0NQ;I4jh*~E@Z<4xI=S6utA0l_fLH_l4GDm(?>P^l-z0t5dK z3v*K#&_HJ }VE8T6KK>?&1=Jojss}AwV$i5^<5ZmcCc&?E{b{2?9SeRn zD5R43P%$A9Reizw!sn=jMyth>Q&AI=s`}NfO?Ojg!Cc@xAZI$4FPJ4JCg$Vl)kV`X zGXovn36C2&TyuTHG{SslJ^uFi%$GcA#(Xb6v(iNkqdW?zq5YpC!|CLHy7HpR`~&>f za)+7{h_1SBuGz(_qsG5_%QHv5O~vb_O|Mi7;Rw)tw>BGdZNzJ}u88sBtMmT;Zj6~; zoqE9{ub968ud>bZ^X0ymXx?8vMe1+A6(Z 44e0rOM^B{C-QBhgq>{u zn+w83v}*4RO1ADSW$M`+z1`yE^n-&=m?}WS@xo|07D$z!=Dkly4a^=GwN+jI-AMf5 zkV%?l_@f;oo;N*{#!9HdgP`UHdlITjn1+8KB}S}bH>^vgrY!r()?PWzXOru4ww1<( zx2i_6+IRYX+={ReiFhr_t`ya*wS30cNZAw?Ixz)sDczK#o7-9-)`tJCQ$`+V#9IU_ zht3)h%m2y6upQ$&`Z;$stS|Uxyt85#WdfC%gVkc|`#m_B7ggEc@{1$>;3AqMhD}^i zYnCoQxF$+@gvYh*$dTWE|LQT$PK=*=F^ZHaUhP??j_&CHy|wJQkL;UJ3;msM?3L_; zV6VX#j|c0KG8)SrbMEom3mmB6_AX5Cbw=_Y)1kM>9u17^8>c<%d7PEB(#zc?Y*%Yd zZxNLiqLI%K%V{yP{hCx|{RidrMctk3? S z%#H-YoMqIm<`P*#cW+yKa#esi<+vEnv8!Ny>|}xJsEdzi*>70a7e#n*O~}lBvk9Mu z>}5s63%+1s&HKJwK=)v(<>ABf($w_YE+u5j47ax@tXzwKr*jKpY(&sc$4YbpnKB&@ zr(!4@bwTBj-;q8Ug 8&-6(? z%Ve!6R|cx~>6|NP*RagwAz530f)M6l$Exh`0Q>uAO(t*7a)Oh)C2e~FedDwpKndSf zwQSPi`RJ=32rs} ^TchzSV5B3-1!;aPlwUOH zT=JVW!Iv*sq=;vWt$GO|aV-K$Y0J}8@ug4A!&8m$?_}LYF|x;sbtAdIfG*zDLn}?C zx(2EFw~?Yj)cOcze?4-m)i-mOm^tfdpZ^Xpyyrbx^1@)e1}p+@s{7qRrO04t(t1~K z@Ssk8(m ;XSFis3Oy1dYo+;viU$0JIK%WV@`ZofC0fQ8w!3@H?8Cg>g_WhZU8XG& z4cbRPvLPCc>-7uc&}uoNgz7^W(E5m7DWwgQH+O8}O<>KiZj1W;!aeQZ)Uusl?dL9# zKynML)@_j&EHnXa0jc``e><@NUx)r-?o=LK?K!6c#ie=BO5pmJ>gvhGz0)2`U2M=j z&e5cgM|WCk(=xx}L!xL6OgpX F zQe$k2Qc_``r_n(S^R2df+uJsc$KS8bos8y 7WY1J6i~W)qkq3u z=cnb9(?m%@;XR%m_I2&k-bGLf0&Kfm>+Pw@&FTmrFK_7fPg84YGiZqvr<{u4 }MpHVRCPstKHUSqY>vEhA>)tuw8#(gTi?52G8Sc}&s?%0T093DP2Q!az4H12;6sLbJt3 zpzR)tnXL7;(y0=UNfV10r`W;~RB!68Wu>FDIM;Z)n`CU+ d{Rqp69~VcGd(4!q}K1s(o@E<|_(tGy)py zX(KjR^vKUjNC%)5=aRcS3kn&i1m-wRwDDCYq0ehK)z$Coe2Hu4hZD#W*~Lr*$vG zK&;Y?LW}bZk!OqVQecCp57tkAbRx=yK0r9}zwaIF%^ly4==PNxL;PBIWIVd N+d3C@4Dj-pa+P?<;; aLcGcI0zf9GHi z1qCCP+xdj~7qIGgbRzAXFbVJd) $?RKZZQ67#lBq?{JAVuC|hg0V&CvLE2b1 zwY04^?AqMHBP8Kr 3Kz)F(Y0N^Htc@c4oS0A68jWzLicJPlGb zkNHSCMP^Kl35CeXJPbKmmr``tw#$K|N0q>3Hw?wVpd98nCbokjC>R9=T~1oQM98bO z*(mD4I}#28eCAi^uMjG+(g44oKVpQz5cH{2x#jfIqW77DgJ}7l?Sho2XS*Y5e2%xy zfa2Db mX92t8-h(R z)L6RJpy6?fKtBbAAD}tJ$4@poGQcYUV14G}^esGm>U_8LIWhY$A3;KYry<- DIt2b#cQQ8x74!=!ba}m9$_@1gn2*X*|Lj33dQJ z{{DSJXsJ%kn{yG$C7yE;5hqh*|MBgh^Yy-MM;j>RJlWs-osxW1rU$JVQQu&iJwNxl zBejM>C+pfnwicB8ugAx%PA2EG1$RXx;13`8Wm2sIL>w}5o{rjlh4-}jMy`BYrS|AQ zw%dR@9$_8>ITRspk4U3=7`ygnS!p3SaG?#22<*p>y8krPQuDoFDu=k5BO{Lv{?(ZK za~?Y)1#s+<-ljRalaRPx2n3}`_;>BO)6!T*P6@;ajG~9F)V*K<9~UdYjIy}`0l#iS zOBsfqEyVM;AI-8Zuy1=It^%wXzZ#wrC=)=@2v#k?Wle;e>~xblb2W_wt(v`+Lz2KK zP%gIqc;Ni>bpb}P*f6q96%|zeX-~dR!`7Cp^!BDxRYI$o@6TKh+vf|+&BF&A-`-$o z9GeEmNu}Lf>rRJ$4!@hpBSDjxZ^wpxlhGO_QuMgK);84u=imMTViBxkoOcQ&%Q ZHm;(mFCGk?6EH1w~PaKu-SeR{XJRyV5U`qXejf5Ohsw(E~c z|7zTUz2Ldb_Z=3?)BhUTp^x*yi)%f^822`(Fj|)@!@WkbA%mI?wB0cyBipgv3-qC( z`P=wWLM`uy&*E<7WW29u>3AeCCYx& ic=D)ciTuH4@i8BIQL{A;1u2 z5m`P&$TUdUSGr*E5!Y;cQt;NBohCOW$@p=S=<;c1ehu3`t_`7%S515@oIlP6&n!?~ zVY%fHTqU>&V5{<<{hL3q)x%q3(DdjbQm}UJJrjDE0iH;0ci$H*X1)eXlV(ron7wJl zh=CP(4N|^lh79zV)bWtrUv1v2^2I@uK7& lkS`=OBX|-8)5~)hKHn}sAIVXWN=KI(_LjlR|HCLv8VUO z3`?Aypl%JlIocG-oXm%V%kM=_gL7Kx!mwd+*WKnq$=t!A-cm5kFIZ3yFPzNrJ99D) z|JcAhd)gFBixuTa<4pZgeI1-LGHLVBSfbhYQ;tE3N7Lgml^erz0{^hV*W1kfi#Rmg z`*?Wlfh }EIQG37js&fLDsnmE_*(h`>aXpM)X0DSoj4oSvzU$(9m3} zYz?_k*<`cysy7J66Gu9N(55tp-q_N#Dt+#S{Xx>7-bYbprcsjr)R$5-Vxq!9eUB(* zSzV_(ku#cnP2b?< !5N6HTzTkl;jRJ#83qssST|>!I}C=G&+=s7kZt-YQEJ_nRTk zExL6| z_O|=RnY#(V;#Sh}`@Dwp&i^*zKV#xT zw4ZK!ezkp`*bunYpM%9lXJ}k&O?~4BZOC-bQ*FJ1vYIDsSmF7-H{ZaXievU@Ja64t zQ0xAT*+AFLOXgH5VHrt$&&$t#zDl$CJvBv^KJG8$z=gl@p59*U#;lI*H -lWfgiJvm)2;JOis)Yy&A)%CB*L~^@9JWg`P>ptzI3X}KX}NdRbS`$d0Q #o=^iH0NXRKtyA2jUV+!H4Y*9T z1q3+c{9va~Q4 Y3T*e+Ea>`&u({&KAH(j6g^l}@ zGokwhi*on~FRWw0-42sZ8L@|0x|0xX=&}BU)AJ%JN5nINr5oknrC8|}yIg??zt#>3 zYw+^>Ix}WitDCTFf@y~Y-e~ZGzXNH33gDJNjwcxKipSE|Bt)+1Q~%I4e`5?tz1=*7 zIff??9_%=B&*w`FazoY(ndlI~LIA~d%{6*4f oWH{SAy2^wy#>togaiE+ zT2KS=@3-Fs+MQb2k;c(gLJSLnTFo(hd&MrkCJ dB-1))%_+K@lLZSNt*Pl0%71)#2&sT_-n%B=sk3|JjY3- z9>E)41Zd>HaRvwl5}J@?U<%+!J1U}zbT)_E%({=XgxVQfrAb=N-jF*StWi)<{{VGo zvBQoW@q%i9ymN?&en=REk?AO&T-9V!K#$!z#Kwwt{76DdnAC0F3qmr;Z$WtWWaULi z73?8A?wp=jU>M0&h>M2W<)SOE0Xow(RID-JmX!fAdi4zM^8(>DVtKuXUgZbh>Q{C0 zeX;4 YliPhC= zO<|N3dk@r?$f?0ASOByA4RR)^c-6&yR`oLUZ68HSWT??kSZpv1D?*kM5?rW=I|=qi z1S!1mrL;Q +-%ZLzir?{Trrdez;^SA2OtZKr)-xWUwf0Pdm_Os_*^1_MqG*08Y3AFZnK#@MaAS z%mgbFL`I!?Wo5Q^>OF`(J6ZQS)ylZm@Yrn*R G=Z%sH?9LOyjjfx(?xp~7&c TD@*(XO~%`3>B?P?IwP~qP_jVpF9*6^cMCmM8KT{ zYXer|T_~&pGQ1*47;w}-Y=eP0*4q+*=7YW_JfhSEb#05vTsNV0?zsc6mH(!M;<7v{ z16e~GF+$wVxwB(P9Gn9t_peWQds?Ma^^r)z$sKlz-bqe+w8>;8TVC@L(>r!A*H z5sp%<@H2v?ji_uV81F{mHyskB8v3uFpY+lqFdCU!(+;;5bB1M+QWGHP )abKPg~s z8OidQ?3)DK?5;~e&|Y{IszjndIo1Sxa?NQVn{u?@U36D$NNa gX#xE=zQ_V{?*zjj1mT0wg)QNrH7q~rrOaj5bJ0;Lg#!B4@Y#S)RQ|T z3YnLH-fu#iAyO3=Td`w6+wTMSq7UjDa&~H$KeN}-63mCU5(nm9Z{ztjeh6`O?CE@r zb;*S@stjitE=48NqB1#g3!p)Btkgf=Rq{uD!NP`;qDv~glqNH2oGL`H#e#R$=z%O= zvYHiJl~}uOJ^ZaQ24`}uluL`QleFo65lul}lTw72Ok-MTp|sn>NfrYsxAG _PO$7Q>GpM)tC_xejRsnRT~|H!9YpCrv2_crBeB`&Qh&oE2PR=2oV zFAW@ICeJaI1T-nhB* ?9?7Wz1 zy!&2La(j98bhiU=e$H+E%h#&=4^$4=@BtMN@}7C*KyrnvJbAzBuMsnfL%9bz7r4_U zviuk45}D{K ox7DCf tL*9{+e1T#@K8ACo(cp8A zOhHflFn&44m4iBLPJ@60kNNo>MP_qsF7WZq5qjG>?d1n1lyOTcItUGm-~AEqh-bUC z)2D8!sg}NsO6ND}9|Y>nysgw?L^moii_X>_t$uB)zhKc@AWN3`0Novra?Ku=_3f<; zsU^KPp4Tba (B!@#!%P#3J-o6#ZkAsYGJLz{gq10d+ z4LM{ou8x`su{i{`s-wP>a@6LH-PqRLTe;-a0!_uUqao>`h|}z?2Gwse+z~?qJdOPH zk+vBqd$s0&u*bTc{d62{Mv|iP`>MD8#0%*uYy0Ha*xCjEStR6z9Q^wt%lEl%Gchfl z$IkvgW*?l^c7(Mhljc8`D*d9C2APDIznY#1kBq49PI FaE_0RQsw_dL>#j4U2|;=;lg)!UWjjLV zf@HqgNq+VfudbNgx3!y2eX|N{f$w(gDKgi+d}FW~9upHj8p5iQ{nfsSu^ic6^rD`$ z!%oS8teH%u+QdUoApefi%C6Uwk^D#<9!s5mZBEP-qk+Mx_$;qHq&9uji!f`jHoB=$ zV87GDjqGO*P4tndjjE|z-Hr8?c(hx;_mapq6Xz|$bmlggQyADjVWP+t z1~WamUz>DJEB@Q lFR{<7_0 z>wzdWei~W~bJ2Ipf7iO#DdXgm8xD?JZA1Jjhv@s=@cy8_Kc&x}e8ECN>2`mCp{P#v z(aJJMHLh;!4Gjt`;h e6-Nljj~+hffxWWT8@c+Vp=;WH0lTF8~%HuLXD@bZ4W z;VBlEOXbM&tO5M#r2JDH`75zJ!5ZOHrSz54`~#E|XX=)Zy{n38s!S0tSU8J1$}j#a zLB&gs)FgA#9Z=Y!u_ou_$ucsbjn{TGuQe=2Q2gPUf4NjBT ^B*h?j+AM)~3d;GTZnPVhC(l6z$$o zD`5G0>CiQO!bsSK6ogo9ltgN@u5@p#SGYa9;)0gb>n5EH6?^y<1~icScVS>~(Bcw> z36T6vnM8)eE1e#)X!;5DuLi=|uU7qKV?p+Jx~@GWwLk#s6~{UlcH;XTTcQ8UuKwLH zOgv|2&8kH*%k3c8!i Z4qpGjf_6wo)!KKNi}g8XfO`05zzx;_Ym$_A7!p&G6t z=^O~Xf~E5?KUSOAG4r~*N*$x519`4VFfW2=uXV^lOP!^)NN9l_mpH|PC(n7?C+%F> za+?)I!4Pn8pQ0YipY ZX9P10U%(skdsIpcU*zdi-_* zAkkCXyrx>jz(|{d9qG{ULIK)>4b&Ibet`-zJO_yx!3M-~5)z07%Gu_>4}ka;TTuvz z8;SI&NI<^{fP!KCF)uG#9qJ= #eB_~taQ?vnKddrR#^8WG%42DVrwhDiK;Y# ?6Ic595Ok|?*6|;XQQelSE zAaN*H7xMdJk9F4)>vuvUt&QJx3xaBarj7w(WNrnr;GD?SLIeupyL#lGh{XYiie%?J z(hmD;g%9~^SoJ<=ok-1*-;b1#_T8(pU$Ce^Cug13gWV$qt;7p2c%cFZh7JSTP*ucu z$nc}A9&qe9G0P5M{b9 6YD@+s+oV|A4ts0#!Byn1La$y`3kMTe ze(q-~MY>#ZmMK3Z)d=vam|rQ;`u+C$0}nDh0fs-C&j|7TF71@@CI~brJO?)=43+^^ zBi@qc!wJe_WCKjI@k=5GJ@tHrMC~EwV-`IpbwFZ(%_Jy0Y^i<<3y7U%703W)i@{l? z6!{p@?%*w=lS3M3Ug}}*GpD8AwyL6P1X}uF`uhdN@__1*E-{0SckL|8v7%>6;TgM1 zCq L=w zp$c(CuyiERy^Xzhivs2tFE=N0X8?hi|E_*FL^8;s3aw6FZPrH#)qgn%%hI22HkQ}b z8ZZCY>OBA9M3mr47zPRnBM{#p*wlPEQPNkyneqO@Tnlw zuR4|gNJ0W+?e3BOfFf#K`J(*Mu|58XnvW=&4fC66^m4Fc=SO}Uy95?%GMq}UTR~6| z*++xy7KCX5P#O%3W#Rw%)C1T_82c$$y2VDlV!^^UlK#t}$qqLu=Qub(Bj~&%G1E(6 z2SAo5crt+A!u*#-VvB%G$iD*c)f=LzGa0Np%V2RJ0m3Z@Wk}@&;T-4VX>{yuvz8pe zXg^mZoUi`lj{>@Es~N(H8NOa`Fd)vY=2&_X@KIJG!ax~Fn2j}Y?Rkmlo!`n4%hobd zvJFimpE4++!Q9I;|0}7aO~U>r26WyJ;DT1|e|t!Olb3r3h*!`FY>wJZFhGac#~oxn zD|5XU57uf+f`wll;4T6tVK7(cdR5V$F{-8jwQHvoc*!hPp#w?g;kp1nW|BE2P~`ic zTs+sFlA>dI5(?mf0#k9$NIS^rxq3vG1#Bt$qO=7L(~n*PS!pOB?LZn$4;j4_=KK%_ z*n)ZCUH>g%t!9MhetO$8AQv75B&L7Q)t249<6^Z)tNbK3kQ$Ixlam{`6H=p*Z>~)D zst#@w{ ;4!pG4@kr_u~N} z$Qy~x`TlvMN!Mq@KK+g<1p~00{{H@krkEk|JoO})-J%k!fas%0l7PMiNYwbEpvlH| zR6a{ji*+c#?KlHBE+kN!!~>RP3(b?04dw>(ldn?DN4Z|$+~ohTn6lSDMG?N9wDPWf zMGJS&Wbeq9n5Cfq_Wg~t-`y`v2r17+58tYE`d`Vj3Rhucjh4WZ>^SjjVw{aQO6!w+ zHP$C0-rWGYEJV#X)%nQq1Mq4}WGfR;B(s!G1T=_@WCzv+9%d9C9na`(3}c`y#IdHx z&m!AKz8e9@*TF4Jr=g @X=5sW_|xG*2% z^>mdr{E*{hkB+UlNwS6~`-(G7O$-d?e#5VYW1Bkd?K?4@&MhTp5L!jU$J=^9!bhq2 zDF;)SJc| nlbEB^q8?nZM~N_Iec_R<-m~NaZr|+WxJs=kNd9XK&OVhWt$}B0{|V z`eXE6i$Kps7XEJO{;a#%WOjW8_xrD3FpTVweqn%)F{US5-d3mVmGX}kI%RaRcLj9? z4({r$um7x_XPMtxiY83Q*;KVFw^j);onZsa2sq} 0-xvmB3>Mo9*+yA}*D^@qFuY8e ^LP 0scZ* z=LdUrABaS6U5jxpjeE&C4*^#1F(F5YU*NeI`zfW+y|&NA7?)a|eE$m;6rW|#!=+Ke zrP01iqe#nK*q!9Ow%bV2{D|StXu&9#I3sTR $O$D;H`5XNB5Tobj^ z`c-?Ez7?8Zv!i7lZOUV2WTm0wq;a@SpsymN?mz|64Vh6>f9sdW=sVBbDFJ8>H)rzG zfCj(oDtL`y8sC*<&XLvhWP-4IuP-u4kH$^Y#r`5$^^W$g^)73qO|zyfE;Pxl*fy6C z;fm_R0|aU4UdmUbm?wH^m%Hc^oxy!w&2;M~ Ot%V?$IY?` TiTRay@OyP=3os4(7p?fI>|RZ?UtZ*5)E*gw zWZc}7EoWyxHnnU (omacA={2V;x)hu%Rj+=#q zl(a-bNZPQD8{R%`O0V^jN%50t=*0VY7Qic2Z4t*Ay=Ub8#LG#N;_HJpRXYyz?F9?H zJqz66-bR_jT8o81#x_ct?1%-&TNzt>5k=Ni+oJbx v9k-X zI9Ysoyr0qKjExVYl@wa<5${_2h1kYC5rx#tiN *7s{U)4NzKRe zozHu{m|PgO1~;qJ4Ky_nB?Xlpm%{tPtSZ`!tlUIeD#`^%!G6NkenO| p%IJ&)Ul8Fr07T)@dy@Pn@$e$+lAQa4z%~HKx?z zzF Vdi8~P1V8=|i=dr$pm{fb z?-lEK+;=2PECq%|0h5#*fDPYYWil!L<(_s;EvvD(SwBA>{Q1)ohl%Cj6B}4-b@I!; z;#jL|8Cg^$!|O96Rcc1AsO{06Q*7!S@0)QXqT#e;!BZsX2$)p*wnN5YJU_R%r&E_4 zTa1G{?vyC@Ia+*I^@B31BvNB8%@i6p{c6q`UKZ&?hB>yi{F}j_teFXm#PQr{Hw4?< zLoD|HR|gNpSG00<9~;`lqCD&nm9ZaVHH#eRn;?#kYx^hpS3=Up1F8Gs5^Y_FO!p(_ z($# @Nz1mXo`1_=n_}*WH;p}W>~Rosq~nf%6gaR74+ym z4fCZdqwkdMWbt+NK2Zsa$7q+W+%5W;-*9lM_AJxYJy0;IdX~4Ij3iUB1TCs*urImq z+084T9InPJ`2PIlMZYAl4{?eYze<~T`iDEvyp^`y!$c!kK$W@a<~JoXae5?mZT7dx zWuovtTrIcrMK1P?1{2SpUx{A753zTABQcS`F*0j;<894!R5?MBc^+*>bt9N?`#XSp z>85W+XI6~tL;GRP;el37!k1q(Vgr7Vd5U!T+`Ml$3Mwbjl>JVjJxfAtRh!#QA!U$i zMXO?Wx!L+7(~bL f+K#Vy}4wP4|Z{=_#xZ4{#*CM`L-} z_|`@>-@YL!nASi;pJAyNTF_x&F;LU;2DAAbEexbwPGjoZ{V2w=@Vz3`vQTPLkDRgb zs8ja5ZE%y1QCw|4dAE5_bg8035=VX1YN`6zM{xCQnj%6|>d~z7i}pw?TWu%x@3Z52 z N|g?+2~u!vtO58Zbrjp)3**t0#L z2v29Euf3 _FL$7^6g<+n}u7+hKO*+yfVy0vO-dR)iBHQL3Z i;z$({pbc)(9Bz6_#R$)CZtM+Z)^{%@ zbNr=A?|;!Vz_|& zM+?yNe*8eoG_yxY^qc83dUT!hRb@;*eMUtC*qqkba5Y9Iv?+aUb Fs836HX(3F zsMp-p$4+V55>-Od;85lTi}(oCce}UuGn}d>r{B t#f1( ~QDJu#tCbaIJkS}zTE zm9X+ YQn1cy2_{mJ^eiJDHRo9=C~h~`STIxG(MJ-R(L+4|Ba%#H zNVjd(Yx>r#wany?x_U9p3l^`Hq@h1Ez=}MY?^u^TM2TgyqUn*0)DU5ONslRs{}z@s z%FD?B`;7iHzew0C-&Y-CqSHLO?td{gpG3!{3=3s9epRpm_88jRm<}7(*`r`DSkJFs zjJry={u$S1P)pOVi)SlqBKlf!D?o^t&!B-2Y=$=xc8WJJl!9%X4tvdp7$i(hql)*Z z7(R#wg9RkBrp>sM@Wn&uFH7}(YV(RY<)^oAEY@EaiK)0BeL?7cFSn9Fz ~dR94Lh|4h%I{qqiG9m-<{^!by0tL?C$U}vpu`dUK z%X(jLP0gV*y9BnPU)xH>dfJTr3l>{%d2XI$6Ko#;?iS=-yrURMIDXIsn jYsqMbNGdRN|Veh=^s2p!*0zRHByA0Pb=ATP&4 z15=O1{##MBmD|h*4lV}>zN3{Kdn@&*8pV( ^ET7$dwp-jU$EdcCSXNF8ShWv0DUGWu=qWKg+rVamt^eR zmjTfi2KxxWy)H0tNHDDG5n`2Y*iXeydD34ygQg?i|60<6!~Q- Yz01AsqZ6&;uGW}dvf%@|zt zb5z%OOwi!ij5&GcPmi?&Odf@+cO4ns;&tBM2G;uN?~r#%uTg*?FOXa(o?Fh_4g3l0 zmQgl?MZI;U38V03$r=v)!SEdIPAszK20eNUSMg{HW@N?~_BWG&I#Q^`fP12>7ex~5 zX7G=dQD7g+Uu4u%oRiC@w6;|+C>buw`vnU_;ZWo#X2t{~mi|cdt?-`3glL|^(p8hA zsesXpgfjTzi5X)cBmrO?ZZ#~}PYi(%!NZd&xc(>f&=UNERR_ag_fOc}zfA3Yn#2C? zE!ji8`)%N|N*M%mTP!Hp;1g2$P)!jWxO#uM*Ay+C+;rf24!9MQx3w!QNz07bP8%rP zqK?$}LBKdld5(#>k&4DSh8$S{`Y_)_J6q1P>{*5Zq{;t`aJGhSOGWX=_le?qy5D1* z6W!jyfBgn(m+&mTBtjDf1S*q_o0q>Mw%~L&s0{-J (e~<_MhO@ l1p$HX8nHeRo98QyoX?VXh2wAi zQ6%Fq41+*GFs2v)=G=y~wJ?uN2^nk5ykNnw!HcOr9e?1nH#H<5-geO;7I@B!6Z-oq z;M=w&%@0;qa }}S zmi4iw_+l5I$~<7!T3STQ^CtrVr&nHgp5CSJL4t}pAGRWI7<3lcUn$NgJcKVZ0#_2S zvuD13-3vNbxDkd!LtNFm@+bKC2Uk~KufXeP?d5b&E(fq0u0CGa6(SzOEGKqUlc<=L zH^7CAk=RljOWXIE
csvjCuh_BZi*}4 z3%DzeTpmdZ0>Q%m@6T`G8XGyee # G1pYt2WYqrv literal 0 HcmV?d00001 From 21b5687d2b7d319241810f79cb187d3bc485a102 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 11:28:40 +0800 Subject: [PATCH 047/524] Published with https://stackedit.io/ --- .../04.Java NIO\347\274\223\345\206\262\345\214\272.md" | 7 +++++++ 1 file changed, 7 insertions(+) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index 71582be..c104bd1 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -1,5 +1,7 @@ #04.Java NIO缓冲区 +Java NIO中的**缓冲区(Buffers)**用于跟**通道(Channels)**交互时使用。如你所知,数据从通道中读取到缓冲区,或从缓冲区中写入到通道。 + Java NIO Buffers are used when interacting with NIO Channels. As you know, data is read from channels into buffers, and written from buffers into channels. A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory block is wrapped in a NIO Buffer object, which provides a set of methods that makes it easier to work with the memory block. @@ -37,12 +39,17 @@ while (bytesRead != -1) { bytesRead = inChannel.read(buf); } aFile.close(); + + + + Buffer Capacity, Position and Limit A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory block is wrapped in a NIO Buffer object, which provides a set of methods that makes it easier to work with the memory block. A Buffer has three properties you need to be familiar with, in order to understand how a Buffer works. These are: + capacity position limit From 74cfbd07add1992d5b61d4547425c7b27e80df59 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 12:26:36 +0800 Subject: [PATCH 048/524] Published with https://stackedit.io/ --- ...va NIO\347\274\223\345\206\262\345\214\272.md" | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index c104bd1..8dd3a44 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -2,11 +2,20 @@ Java NIO中的**缓冲区(Buffers)**用于跟**通道(Channels)**交互时使用。如你所知,数据从通道中读取到缓冲区,或从缓冲区中写入到通道。 -Java NIO Buffers are used when interacting with NIO Channels. As you know, data is read from channels into buffers, and written from buffers into channels. +缓冲区本质上是一个内存块,在这个块中,你可以进行写入和读取操作。Java NIO将这个内存块用缓存区包装起来,并提供了一系列的用于操作这个内存块的API。 + +##缓冲区的基本用法(Basic Buffer Usage) + +利用缓冲区读写数据通常遵循这个小4个步骤: + +* 写入数据到缓冲区; +* 调用buffer.flip()方法; +* 从缓冲区中读取数据; +* 调用buffer.clear()或buffer.compact()方法。 + +当你往缓冲区写入数据的时候,缓冲区会跟踪记录你写入的数据量。当你需要缓冲区读取数据时,你需要调用**`flip()`**方法将缓冲区从**写入模式**切换为**读取模式**。在读取模式中,你可以读取之前往缓冲区写入的所有数据。 -A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory block is wrapped in a NIO Buffer object, which provides a set of methods that makes it easier to work with the memory block. -Basic Buffer Usage Using a Buffer to read and write data typically follows this little 4-step process: From 3c44efde4e7b83f9002e1f19f2395f2460bd4ee7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 12:33:47 +0800 Subject: [PATCH 049/524] Published with https://stackedit.io/ --- ....Java NIO\347\274\223\345\206\262\345\214\272.md" | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index 8dd3a44..6230621 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -13,17 +13,9 @@ Java NIO中的**缓冲区(Buffers)**用于跟**通道(Channels)**交互 * 从缓冲区中读取数据; * 调用buffer.clear()或buffer.compact()方法。 -当你往缓冲区写入数据的时候,缓冲区会跟踪记录你写入的数据量。当你需要缓冲区读取数据时,你需要调用**`flip()`**方法将缓冲区从**写入模式**切换为**读取模式**。在读取模式中,你可以读取之前往缓冲区写入的所有数据。 +当你往缓冲区写入数据的时候,缓冲区会跟踪记录你写入的数据量。当你需要缓冲区读取数据时,你需要调用`flip()`方法将缓冲区从**写入模式**切换为**读取模式**。在读取模式中,你可以读取之前往缓冲区写入的所有数据。 - - -Using a Buffer to read and write data typically follows this little 4-step process: - -Write data into the Buffer -Call buffer.flip() -Read data out of the Buffer -Call buffer.clear() or buffer.compact() -When you write data into a buffer, the buffer keeps track of how much data you have written. Once you need to read the data, you need to switch the buffer from writing mode into reading mode using the flip() method call. In reading mode the buffer lets you read all the data written into the buffer. +当你读取完数据之后,你需要清空缓冲区,以便可以写入数据。你可以通过两种方式来完成:调用`clear()`或`compact()`方法。__`clear()`方法会清空整个缓冲区的数据。而`compact()`方法只会清空已经读取过的数据,尚未读取过的数据会被移动到缓冲区的前端,以便下次读取。__ Once you have read all the data, you need to clear the buffer, to make it ready for writing again. You can do this in two ways: By calling clear() or by calling compact(). The clear() method clears the whole buffer. The compact() method only clears the data which you have already read. Any unread data is moved to the beginning of the buffer, and data will now be written into the buffer after the unread data. From 04c4dc970b86af5674465c5d5fc3a14ee456f165 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 15:38:17 +0800 Subject: [PATCH 050/524] Published with https://stackedit.io/ --- ...4.Java NIO\347\274\223\345\206\262\345\214\272.md" | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index 6230621..afb3537 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -15,12 +15,11 @@ Java NIO中的**缓冲区(Buffers)**用于跟**通道(Channels)**交互 当你往缓冲区写入数据的时候,缓冲区会跟踪记录你写入的数据量。当你需要缓冲区读取数据时,你需要调用`flip()`方法将缓冲区从**写入模式**切换为**读取模式**。在读取模式中,你可以读取之前往缓冲区写入的所有数据。 -当你读取完数据之后,你需要清空缓冲区,以便可以写入数据。你可以通过两种方式来完成:调用`clear()`或`compact()`方法。__`clear()`方法会清空整个缓冲区的数据。而`compact()`方法只会清空已经读取过的数据,尚未读取过的数据会被移动到缓冲区的前端,以便下次读取。__ +当你读取完数据之后,你需要清空缓冲区,以便可以写入数据。你可以通过两种方式来完成:调用`clear()`或`compact()`方法。__`clear()`方法会清空整个缓冲区的数据。而`compact()`方法只会清空已经读取过的数据,尚未读取过的数据会被移动到缓冲区的前端,以便下次继续读取。__ -Once you have read all the data, you need to clear the buffer, to make it ready for writing again. You can do this in two ways: By calling clear() or by calling compact(). The clear() method clears the whole buffer. The compact() method only clears the data which you have already read. Any unread data is moved to the beginning of the buffer, and data will now be written into the buffer after the unread data. - -Here is a simple Buffer usage example, with the write, flip, read and clear operations maked in bold: +简单示例: +```Java RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); FileChannel inChannel = aFile.getChannel(); @@ -40,9 +39,9 @@ while (bytesRead != -1) { bytesRead = inChannel.read(buf); } aFile.close(); +``` - - + Buffer Capacity, Position and Limit From a15cfb955bf9e1d4428bded4e739fd15e7f3e004 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 16:09:40 +0800 Subject: [PATCH 051/524] Published with https://stackedit.io/ --- ...IO\347\274\223\345\206\262\345\214\272.md" | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index afb3537..c6b4667 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -41,52 +41,51 @@ while (bytesRead != -1) { aFile.close(); ``` - +##Capacity, Position和Limit -Buffer Capacity, Position and Limit +缓冲区本质上是一个内存块,在这个块中,你可以进行写入和读取操作。Java NIO将这个内存块用缓存区包装起来,并提供了一系列的用于操作这个内存块的API。 + +如果你想知道缓冲区是如何工作的,那么你需要理解缓冲区的三个属性,它们分别是: + +* 容量(Capacity) +* 位置(Position) +* 极限(Limit) -A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory block is wrapped in a NIO Buffer object, which provides a set of methods that makes it easier to work with the memory block. -A Buffer has three properties you need to be familiar with, in order to understand how a Buffer works. These are: +**position**和**limit**在读取模式/写入模式中具有不同的含义。而**capacity**在任何情况都具有同一含义:**缓冲区的容量大小。** +下面这个图描绘了capacity,position和limit在读取模式和写入模式中的含义: -capacity -position -limit -The meaning of position and limit depends on whether the Buffer is in read or write mode. Capacity always means the same, no matter the buffer mode. + -Here is an illustration of capacity, position and limit in write and read modes. The explanation follows in the sections after the illustration. +###Capacity -Java NIO: Buffer capacity, position and limit in write and read mode. -Buffer capacity, position and limit in write and read mode. -Capacity +做为一个内存块,缓冲区有固定的大小,称之为:**容量(capcity)**。你只能往缓冲区中写入固定大小的bytes,long,chars等类型数据。一旦缓冲区慢后,你需要清空它(读取数据或clear())才能继续写入数据。 -Being a memory block, a Buffer has a certain fixed size, also called its "capacity". You can only write capacity bytes, longs, chars etc. into the Buffer. Once the Buffer is full, you need to empty it (read the data, or clear it) before you can write more data into it. +###Position -Position +当你往缓冲区写入数据时,实际上你是往缓冲区中的指定的位置写入数据。这个位置初始值为0,当往缓冲区写入数据时,position会指向下一个可写入的内存单元。postion的最大值为capacity-1。 -When you write data into the Buffer, you do so at a certain position. Initially the position is 0. When a byte, long etc. has been written into the Buffer the position is advanced to point to the next cell in the buffer to insert data into. Position can maximally become capacity - 1. +当你从缓冲区读取数据时,你同样的是从position指定的位置读取数据。当你调用`flip()`方法使缓冲区由**写入模式**切换成**读取模式**后,position会重置为0。当从position指定单元读数据后,postion会移至下一个可读取单元。 -When you read data from a Buffer you also do so from a given position. When you flip a Buffer from writing mode to reading mode, the position is reset back to 0. As you read data from the Buffer you do so from position, and position is advanced to next position to read. +###Limit -Limit +在**写入模式**中,limit指定的是能写入数据量的大小。在写入模式中,limit的值等于capacity的值。 -In write mode the limit of a Buffer is the limit of how much data you can write into the buffer. In write mode the limit is equal to the capacity of the Buffer. +当调用`flip()`方法使缓冲区切换成**读取模式**后,limit会重置为你能读取的数据量的大小。因此,在调用`flip()`方法后,limit重置为position的值,而position重置为0。 -When flipping the Buffer into read mode, limit means the limit of how much data you can read from the data. Therefore, when flipping a Buffer into read mode, limit is set to write position of the write mode. In other words, you can read as many bytes as were written (limit is set to the number of bytes written, which is marked by position). +##Buffer Types -Buffer Types +Java NIO提供了一下缓冲区类型: -Java NIO comes with the following Buffer types: +* ByteBuffer +* MappedByteBuffer +* ShortBuffer +* IntBuffer +* LongBuffer +* FloatBuffer +* DoubleBuffer -ByteBuffer -MappedByteBuffer -CharBuffer -DoubleBuffer -FloatBuffer -IntBuffer -LongBuffer -ShortBuffer As you can see, these Buffer types represent different data types. In other words, they let you work with the bytes in the buffer as char, short, int, long, float or double instead. The MappedByteBuffer is a bit special, and will be covered in its own text. From 66b4908a2879fe4e830fdc614b113faddc3b8c32 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 16:11:05 +0800 Subject: [PATCH 052/524] Published with https://stackedit.io/ --- ...a NIO\347\274\223\345\206\262\345\214\272.md" | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index c6b4667..faa64bd 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -90,7 +90,7 @@ As you can see, these Buffer types represent different data types. In other word The MappedByteBuffer is a bit special, and will be covered in its own text. -Allocating a Buffer +###Allocating a Buffer To obtain a Buffer object you must first allocate it. Every Buffer class has an allocate() method that does this. Here is an example showing the allocation of a ByteBuffer, with a capacity of 48 bytes: @@ -98,7 +98,7 @@ ByteBuffer buf = ByteBuffer.allocate(48); Here is an example allocating a CharBuffer with space for 1024 characters: CharBuffer buf = CharBuffer.allocate(1024); -Writing Data to a Buffer +###Writing Data to a Buffer You can write data into a Buffer in two ways: @@ -112,7 +112,7 @@ Here is an example that writes data into a Buffer via the put() method: buf.put(127); There are many other versions of the put() method, allowing you to write data into the Buffer in many different ways. For instance, writing at specific positions, or writing an array of bytes into the buffer. See the JavaDoc for the concrete buffer implementation for more details. -flip() +###flip() The flip() method switches a Buffer from writing mode to reading mode. Calling flip() sets the position back to 0, and sets the limit to where position just was. @@ -133,11 +133,11 @@ Here is an example that reads data from a Buffer using the get() method: byte aByte = buf.get(); There are many other versions of the get() method, allowing you to read data from the Buffer in many different ways. For instance, reading at specific positions, or reading an array of bytes from the buffer. See the JavaDoc for the concrete buffer implementation for more details. -rewind() +###rewind() The Buffer.rewind() sets the position back to 0, so you can reread all the data in the buffer. The limit remains untouched, thus still marking how many elements (bytes, chars etc.) that can be read from the Buffer. -clear() and compact() +###clear() and compact() Once you are done reading data out of the Buffer you have to make the Buffer ready for writing again. You can do so either by calling clear() or by calling compact(). @@ -149,7 +149,7 @@ If there is still unread data in the Buffer, and you want to read it later, but compact() copies all unread data to the beginning of the Buffer. Then it sets position to right after the last unread element. The limit property is still set to capacity, just like clear() does. Now the Buffer is ready for writing, but you will not overwrite the unread data. -mark() and reset() +###mark() and reset() You can mark a given position in a Buffer by calling the Buffer.mark() method. You can then later reset the position back to the marked position by calling the Buffer.reset() method. Here is an example: @@ -162,7 +162,7 @@ equals() and compareTo() It is possible to compare two buffers using equals() and compareTo(). -equals() +###equals() Two buffers are equal if: @@ -171,7 +171,7 @@ They have the same amount of remaining bytes, chars etc. in the buffer. All remaining bytes, chars etc. are equal. As you can see, equals only compares part of the Buffer, not every single element inside it. In fact, it just compares the remaining elements in the Buffer. -compareTo() +###compareTo() The compareTo() method compares the remaining elements (bytes, chars etc.) of the two buffers, for use in e.g. sorting routines. A buffer is considered "smaller" than another buffer if: From 072e10e7387d16509de4666cb37aafcd0b40f496 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 16:13:26 +0800 Subject: [PATCH 053/524] Published with https://stackedit.io/ --- ...ava NIO\347\274\223\345\206\262\345\214\272.md" | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index faa64bd..600359d 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -94,10 +94,16 @@ The MappedByteBuffer is a bit special, and will be covered in its own text. To obtain a Buffer object you must first allocate it. Every Buffer class has an allocate() method that does this. Here is an example showing the allocation of a ByteBuffer, with a capacity of 48 bytes: +```Java ByteBuffer buf = ByteBuffer.allocate(48); +``` + Here is an example allocating a CharBuffer with space for 1024 characters: +```Java CharBuffer buf = CharBuffer.allocate(1024); +``` + ###Writing Data to a Buffer You can write data into a Buffer in two ways: @@ -106,10 +112,13 @@ Write data from a Channel into a Buffer Write data into the Buffer yourself, via the buffer's put() methods. Here is an example showing how a Channel can write data into a Buffer: +```Java int bytesRead = inChannel.read(buf); //read into buffer. Here is an example that writes data into a Buffer via the put() method: buf.put(127); +``` + There are many other versions of the put() method, allowing you to write data into the Buffer in many different ways. For instance, writing at specific positions, or writing an array of bytes into the buffer. See the JavaDoc for the concrete buffer implementation for more details. ###flip() @@ -126,11 +135,14 @@ Read data from the buffer into a channel. Read data from the buffer yourself, using one of the get() methods. Here is an example of how you can read data from a buffer into a channel: +```Java //read from buffer into channel. int bytesWritten = inChannel.write(buf); Here is an example that reads data from a Buffer using the get() method: byte aByte = buf.get(); +``` + There are many other versions of the get() method, allowing you to read data from the Buffer in many different ways. For instance, reading at specific positions, or reading an array of bytes from the buffer. See the JavaDoc for the concrete buffer implementation for more details. ###rewind() @@ -153,12 +165,14 @@ compact() copies all unread data to the beginning of the Buffer. Then it sets po You can mark a given position in a Buffer by calling the Buffer.mark() method. You can then later reset the position back to the marked position by calling the Buffer.reset() method. Here is an example: +```Java buffer.mark(); //call buffer.get() a couple of times, e.g. during parsing. buffer.reset(); //set position back to mark. equals() and compareTo() +``` It is possible to compare two buffers using equals() and compareTo(). From 1575db25d1d57fe156135b1de56541c6357fca2a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 16:31:03 +0800 Subject: [PATCH 054/524] Published with https://stackedit.io/ --- ...IO\347\274\223\345\206\262\345\214\272.md" | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index 600359d..aa19fa8 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -86,19 +86,15 @@ Java NIO提供了一下缓冲区类型: * FloatBuffer * DoubleBuffer -As you can see, these Buffer types represent different data types. In other words, they let you work with the bytes in the buffer as char, short, int, long, float or double instead. - -The MappedByteBuffer is a bit special, and will be covered in its own text. - ###Allocating a Buffer -To obtain a Buffer object you must first allocate it. Every Buffer class has an allocate() method that does this. Here is an example showing the allocation of a ByteBuffer, with a capacity of 48 bytes: +要获得缓冲区,你需要为它开辟空间。每一个缓冲区类都有一个`allocate()`方法用于开辟内存空间。下面这个代码示例显示了如何开辟48个字节的缓冲区。 ```Java ByteBuffer buf = ByteBuffer.allocate(48); ``` -Here is an example allocating a CharBuffer with space for 1024 characters: +下面的代码显示了如何开辟1024个字符的内存空间: ```Java CharBuffer buf = CharBuffer.allocate(1024); @@ -106,20 +102,24 @@ CharBuffer buf = CharBuffer.allocate(1024); ###Writing Data to a Buffer -You can write data into a Buffer in two ways: +你可以通过两种方式往缓冲区中写入数据: + +* 从通道中写入数据到缓冲区。 +* 通过缓冲区的`put()`方法直接往缓冲区写入数据。 -Write data from a Channel into a Buffer -Write data into the Buffer yourself, via the buffer's put() methods. -Here is an example showing how a Channel can write data into a Buffer: +下面的代码演示了从通道中写入数据到缓冲区: ```Java int bytesRead = inChannel.read(buf); //read into buffer. -Here is an example that writes data into a Buffer via the put() method: +``` + +下面的代码演示了通过`put()`方法直接往缓冲区写入数据: +```Java buf.put(127); ``` -There are many other versions of the put() method, allowing you to write data into the Buffer in many different ways. For instance, writing at specific positions, or writing an array of bytes into the buffer. See the JavaDoc for the concrete buffer implementation for more details. +有很多重载的`put`方法方便你往缓冲区写入数据。例如,将数据写入到指定位置,或者将字节数组写入缓冲区。具体的方法请查阅API。 ###flip() From c6c76840b759d57d650ec0639f6ebc84f109e678 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 4 Sep 2014 16:36:49 +0800 Subject: [PATCH 055/524] Published with https://stackedit.io/ --- Java-NIO/05.Java NIO Scatter, Gather.md | 47 +++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Java-NIO/05.Java NIO Scatter, Gather.md diff --git a/Java-NIO/05.Java NIO Scatter, Gather.md b/Java-NIO/05.Java NIO Scatter, Gather.md new file mode 100644 index 0000000..66f3482 --- /dev/null +++ b/Java-NIO/05.Java NIO Scatter, Gather.md @@ -0,0 +1,47 @@ +#05.Java NIO Scatter, Gather + +Java NIO comes with built-in scatter / gather support. Scatter / gather are concepts used in reading from, and writing to channels. + +A scattering read from a channel is a read operation that reads data into more than one buffer. Thus, the channel "scatters" the data from the channel into multiple buffers. + +A gathering write to a channel is a write operation that writes data from more than one buffer into a single channel. Thus, the channel "gathers" the data from multiple buffers into one channel. + +Scatter / gather can be really useful in situations where you need to work with various parts of the transmitted data separately. For instance, if a message consists of a header and a body, you might keep the header and body in separate buffers. Doing so may make it easier for you to work with header and body separately. + +Scattering Reads + +A "scattering read" reads data from a single channel into multiple buffers. Here is an illustration of that principle: + +Here is an illustration of the Scatter principle: + +Java NIO: Scattering Read +Java NIO: Scattering Read +Here is a code example that shows how to perform a scattering read: + +ByteBuffer header = ByteBuffer.allocate(128); +ByteBuffer body = ByteBuffer.allocate(1024); + +ByteBuffer[] bufferArray = { header, body }; + +channel.read(buffers); +Notice how the buffers are first inserted into an array, then the array passed as parameter to the channel.read() method. The read() method then writes data from the channel in the sequence the buffers occur in the array. Once a buffer is full, the channel moves on to fill the next buffer. + +The fact that scattering reads fill up one buffer before moving on to the next, means that it is not suited for dynamically sized message parts. In other words, if you have a header and a body, and the header is fixed size (e.g. 128 bytes), then a scattering read works fine. + +Gathering Writes + +A "gathering write" writes data from multiple buffers into a single channel. Here is an illustration of that principle: + +Java NIO: Gathering Write +Java NIO: Gathering Write +Here is a code example that shows how to perform a gathering write: + +ByteBuffer header = ByteBuffer.allocate(128); +ByteBuffer body = ByteBuffer.allocate(1024); + +//write data into buffers + +ByteBuffer[] bufferArray = { header, body }; + +channel.write(buffers); +The array of buffers are passed into the write() method, which writes the content of the buffers in the sequence they are encountered in the array. Only the data between position and limit of the buffers is written. Thus, if a buffer has a capacity of 128 bytes, but only contains 58 bytes, only 58 bytes are written from that buffer to the channel. Thus, a gathering write works fine with dynamically sized message parts, in contrast to scattering reads. \ No newline at end of file From 4e04acbf1464acbb968a5e96ff7505dd4031449a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 14:12:33 +0800 Subject: [PATCH 056/524] Create README.md --- Java-Concurrency-Multithreading/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Java-Concurrency-Multithreading/README.md diff --git a/Java-Concurrency-Multithreading/README.md b/Java-Concurrency-Multithreading/README.md new file mode 100644 index 0000000..41cada4 --- /dev/null +++ b/Java-Concurrency-Multithreading/README.md @@ -0,0 +1 @@ + 翻译自:http://tutorials.jenkov.com/java-concurrency/index.html From 2e3a79297875fe1708267a41c3a582fab9650c87 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 14:15:18 +0800 Subject: [PATCH 057/524] Published with https://stackedit.io/ --- ...5\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" diff --git "a/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" new file mode 100644 index 0000000..5676619 --- /dev/null +++ "b/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" @@ -0,0 +1 @@ +# 01.Java 并发与多线程 \ No newline at end of file From 16146b93c345ca95a3f9293c699fd308670fe1e0 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 14:16:08 +0800 Subject: [PATCH 058/524] Published with https://stackedit.io/ --- ...16\345\244\232\347\272\277\347\250\213.md" | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" index 5676619..9b43d3f 100644 --- "a/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" @@ -1 +1,20 @@ -# 01.Java 并发与多线程 \ No newline at end of file +# 01.Java 并发与多线程 + +Back in the old days a computer had a single CPU, and was only capable of executing a single program at a time. Later came multitasking which meant that computers could execute multiple programs (AKA tasks or processes) at the same time. It wasn't really "at the same time" though. The single CPU was shared between the programs. The operating system would switch between the programs running, executing each of them for a little while before switching. + +Along with multitasking came new challenges for software developers. Programs can no longer assume to have all the CPU time available, nor all memory or any other computer resources. A "good citizen" program should release all resources it is no longer using, so other programs can use them. + +Later yet came multithreading which mean that you could have multiple threads of execution inside the same program. A thread of execution can be thought of as a CPU executing the program. When you have multiple threads executing the same program, it is like having multiple CPU's execute within the same program. + +Mulithreading is even more challenging than multitasking. The threads are executing within the same program and are hence reading and writing the same memory simultanously. This can result in errors not seen in a singlethreaded program. Some of these errors may not be seen on single CPU machines, because two threads never really execute "simultanously". Modern computers, though, come with multi core CPU's. This means that separate threads can be executed by separate cores simultanously. + +If a thread reads a memory location while another thread writes to it, what value will the first thread end up reading? The old value? The value written by the second thread? Or a value that is a mix between the two? Or, if two threads are writing to the same memory location simultanously, what value will be left when they are done? The value written by the first thread? The value written by the second thread? Or a mix of the two values written? Without proper precautions any of these outcomes are possible. The behaviour would not even be predictable. The outcome could change from time to time. + + +##Multithreading and Concurrency in Java + +Java was one of the first languages to make multithreading easily available to developers. Java had multithreading capabilities from the very beginning. Therefore, Java developers often face the problems described above. That is the reason I am writing this trail on Java concurrency. As notes to myself, and any fellow Java developer whom may benefit from it. + +The trail will primarily be concerned with multithreading in Java, but some of the problems occurring in multithreading are similar to problems occurring in multitasking and in distributed systems. References to multitasking and distributed systems may therefore occur in this trail too. Hence the word "concurrency" rather than "multithreading". + +This trail is still work in progress. Texts will be published whenver time is available to write them. Below is a list of the current texts in this trail. The list is also repeated at the top right of every page in the trail. \ No newline at end of file From 28d530d55e6b171e6ace3345e97c6c736fe83814 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 14:17:21 +0800 Subject: [PATCH 059/524] Published with https://stackedit.io/ --- ...72\277\347\250\213\347\232\204\345\245\275\345\244\204.md" | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 "Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" diff --git "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" new file mode 100644 index 0000000..b920339 --- /dev/null +++ "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" @@ -0,0 +1,4 @@ +#02.多线程的好处 + + +> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file From 222d6d0a6fb9a8371996bed29c6f310f0bf0d710 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 15:02:22 +0800 Subject: [PATCH 060/524] Published with https://stackedit.io/ --- ...4\270\216\345\244\232\347\272\277\347\250\213.md" | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" index 9b43d3f..423d594 100644 --- "a/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" @@ -1,15 +1,19 @@ # 01.Java 并发与多线程 -Back in the old days a computer had a single CPU, and was only capable of executing a single program at a time. Later came multitasking which meant that computers could execute multiple programs (AKA tasks or processes) at the same time. It wasn't really "at the same time" though. The single CPU was shared between the programs. The operating system would switch between the programs running, executing each of them for a little while before switching. +在以前,一台计算机只有一个CPU,而且在同一时间只能执行一个应用程序。后来引入了多任务的概念,这意味着计算机能再同一时间内执行多个应用程序。虽然,这并不是真正意义上的“同时”。多个应用程序共享计算机的CPU,操作系统在极小的时间切片内对应用程序进行切换以获得CPU资源。 -Along with multitasking came new challenges for software developers. Programs can no longer assume to have all the CPU time available, nor all memory or any other computer resources. A "good citizen" program should release all resources it is no longer using, so other programs can use them. +多任务的引入对软件开发者带来的新的挑战。应用程序不再能占用所有的CPU时间和所有的内存以及其他计算机资源。同时,一个好的应用程序在退出之后应该释放所有的系统系统以供其它应用程序使用。 + +不久之后,多线程的概念被引入,这意味着,在一个应用程序中可以拥有多个执行线程。A thread of execution can be thought of as a CPU executing the program. 当一个应用程序有多个线程执行时,它就像拥有多个CPU在执行任务。 + +多线程比多任务带来的挑战更加巨大。多线程意味着,在一个应用程序内部,可以存在多个线程同时地对内存进行读写操作。它会出现一些在单线程中永远不会出现的错误。有些错误也许在单个CPU的计算机上也不会出现(因为在单个CPU的计算机上,两个线程永远不可能真正意义上的同时执行)。现代计算机,基本都拥有多个CPU内核,线程可以通过独占内核来实现真正意义上的并行。 -Later yet came multithreading which mean that you could have multiple threads of execution inside the same program. A thread of execution can be thought of as a CPU executing the program. When you have multiple threads executing the same program, it is like having multiple CPU's execute within the same program. -Mulithreading is even more challenging than multitasking. The threads are executing within the same program and are hence reading and writing the same memory simultanously. This can result in errors not seen in a singlethreaded program. Some of these errors may not be seen on single CPU machines, because two threads never really execute "simultanously". Modern computers, though, come with multi core CPU's. This means that separate threads can be executed by separate cores simultanously. If a thread reads a memory location while another thread writes to it, what value will the first thread end up reading? The old value? The value written by the second thread? Or a value that is a mix between the two? Or, if two threads are writing to the same memory location simultanously, what value will be left when they are done? The value written by the first thread? The value written by the second thread? Or a mix of the two values written? Without proper precautions any of these outcomes are possible. The behaviour would not even be predictable. The outcome could change from time to time. +如果一个线程读取内存位置,而另一个线程写入的话,会在第一个线程结束了什么价值看什么?旧的价值?写由所述第二线程的值?或者一个值,两者之间的混合?或者,如果两个线程都写入同一个存储位置simultanously,什么价值都做的时候,他们会留下?写的第一线程的值?写由所述第二线程的值?或两个值的组合写的?如果没有适当的预防措施,所有这些结果是可能的。行为甚至不会预测。其结果可能会改变,不时。 + ##Multithreading and Concurrency in Java From 392262a7dbb9ace79691639ef784e094eedad559 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 15:20:56 +0800 Subject: [PATCH 061/524] Published with https://stackedit.io/ --- ...21\344\270\216\345\244\232\347\272\277\347\250\213.md" | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git "a/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" index 423d594..b024e2c 100644 --- "a/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" @@ -8,14 +8,10 @@ 多线程比多任务带来的挑战更加巨大。多线程意味着,在一个应用程序内部,可以存在多个线程同时地对内存进行读写操作。它会出现一些在单线程中永远不会出现的错误。有些错误也许在单个CPU的计算机上也不会出现(因为在单个CPU的计算机上,两个线程永远不可能真正意义上的同时执行)。现代计算机,基本都拥有多个CPU内核,线程可以通过独占内核来实现真正意义上的并行。 +如果一个线程往一块内存读取数据,而同时另一个线程往同样的地址写入数据,那么第一个线程读取的值是多少?原来的值?或是被第二个线程写入的值?或是两者混合的值?再举个例子,如果有两个线程同时往一块内存地址写入数据,那么这块内存最终的值是什么?第一个线程写入的值?还是第二个线程写入的值?还是两者的混合?如果没有恰当的预防措施,所有的这些结果都是可能的。线程的执行行为不能预测,所以最终的计算结果也跟着不同。 -If a thread reads a memory location while another thread writes to it, what value will the first thread end up reading? The old value? The value written by the second thread? Or a value that is a mix between the two? Or, if two threads are writing to the same memory location simultanously, what value will be left when they are done? The value written by the first thread? The value written by the second thread? Or a mix of the two values written? Without proper precautions any of these outcomes are possible. The behaviour would not even be predictable. The outcome could change from time to time. - -如果一个线程读取内存位置,而另一个线程写入的话,会在第一个线程结束了什么价值看什么?旧的价值?写由所述第二线程的值?或者一个值,两者之间的混合?或者,如果两个线程都写入同一个存储位置simultanously,什么价值都做的时候,他们会留下?写的第一线程的值?写由所述第二线程的值?或两个值的组合写的?如果没有适当的预防措施,所有这些结果是可能的。行为甚至不会预测。其结果可能会改变,不时。 - - -##Multithreading and Concurrency in Java +##Java的多线程与并发(Multithreading and Concurrency in Java) Java was one of the first languages to make multithreading easily available to developers. Java had multithreading capabilities from the very beginning. Therefore, Java developers often face the problems described above. That is the reason I am writing this trail on Java concurrency. As notes to myself, and any fellow Java developer whom may benefit from it. From 082c654481bd41ac8cbe03ffdffe4dd7e364547a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 15:43:19 +0800 Subject: [PATCH 062/524] Published with https://stackedit.io/ --- ...13\347\232\204\345\245\275\345\244\204.md" | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" index b920339..fc187e8 100644 --- "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" +++ "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" @@ -1,4 +1,62 @@ #02.多线程的好处 +尽管多线程带来的一些挑战,也让先写应用程序变得复杂,但它也带来了一系列好处: + +* 更好的资源利用率 +* 在某些情况下,让程序变得更加简单 +* More responsive programs + + +##更好的资源利用率(Better resource utilization) + +试想一下,一个读取和处理本地系统文件的应用程序。比方说,从磁盘读取AF文件需要5秒,处理需要2秒,处理两个文件过程如下: + +``` +读取文件A消耗5s +处理文件A消耗2s +读取文件B消耗5s +处理文件B消耗2s +------------- +总共消耗时间14s +``` + + + +When reading the file from disk most of the CPU time is spent waiting for the disk to read the data. The CPU is pretty much idle during that time. It could be doing something else. By changing the order of the operations, the CPU could be better utilized. Look at this ordering: + + 5 seconds reading file A + 5 seconds reading file B + 2 seconds processing file A + 2 seconds processing file B +----------------------- + 12 seconds total +The CPU waits for the first file to be read. Then it starts the read of the second file. While the second file is being read, the CPU processes the first file. Remember, while waiting for the file to be read from disk, the CPU is mostly idle. + +In general, the CPU can be doing other things while waiting for IO. It doesn't have to be disk IO. It can be network IO as well, or input from a user at the machine. Network and disk IO is often a lot slower than CPU's and memory IO. + + +Simpler Program Design + +If you were to program the above ordering of reading and processing by hand in a singlethreaded application, you would have to keep track of both the read and processing state of each file. Instead you can start two threads that each just reads and processes a single file. Each of these threads will be blocked while waiting for the disk to read its file. While waiting, other threads can use the CPU to process the parts of the file they have already read. The result is, that the disk is kept busy at all times, reading from various files into memory. This results in a better utilization of both the disk and the CPU. It is also easier to program, since each thread only has to keep track of a single file. + +More responsive programs + +Another common goal for turning a singlethreaded application into a multithreaded application is to achieve a more responsive application. Imagine a server application that listens on some port for incoming requests. when a request is received, it handles the request and then goes back to listening. The server loop is sketched below: + + + while(server is active){ + listen for request + process request + } +If the request takes a long time to process, no new clients can send requests to the server for that duration. Only while the server is listening can requests be received. + +An alternate design would be for the listening thread to pass the request to a worker thread, and return to listening immediatedly. The worker thread will process the request and send a reply to the client. This design is sketched below: + + + while(server is active){ + listen for request + hand request to worker thread + } +This way the server thread will be back at listening sooner. Thus more clients can send requests to the server. The server has become more responsive. + +The same is true for desktop applications. If you click a button that starts a long task, and the thread executing the task is the thread updating the windows, buttons etc., then the application will appear unresponsive while the task executes. Instead the task can be handed off to a worker thread. While the worker thread is busy with the task, the window thread is free to respond to other user requests. When the worker thread is done it signals the window thread. The window thread can then update the application windows with the result of the task. The program with the worker thread design will appear more responsive to the user. -> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file From d7289e5b020fb756e0129e3c463cb24f4d239ad6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 15:53:20 +0800 Subject: [PATCH 063/524] Published with https://stackedit.io/ --- ...13\347\232\204\345\245\275\345\244\204.md" | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" index fc187e8..a6ea4d9 100644 --- "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" +++ "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" @@ -20,25 +20,26 @@ 总共消耗时间14s ``` +当从磁盘读取文件时,大部分的CPU时间都消耗在了等待磁盘读取数据,而在这段时间内,CPU大部分时间内都是空闲的,它原本可以用来做其他操作。改变操作的顺序,可以让CPU得到更高的利用率。如下所示: +``` +读取文件A消耗5s +读取文件B消耗5s + 处理文件A消耗2s +处理文件B消耗2s +------------- +总共消耗时间12s +``` -When reading the file from disk most of the CPU time is spent waiting for the disk to read the data. The CPU is pretty much idle during that time. It could be doing something else. By changing the order of the operations, the CPU could be better utilized. Look at this ordering: - - 5 seconds reading file A - 5 seconds reading file B + 2 seconds processing file A - 2 seconds processing file B ------------------------ - 12 seconds total -The CPU waits for the first file to be read. Then it starts the read of the second file. While the second file is being read, the CPU processes the first file. Remember, while waiting for the file to be read from disk, the CPU is mostly idle. +当CPU读取往文件A后,则紧随着读取文件B,在此同时处理文件A。需要谨记的是,在等带磁盘读取文件时,CPU大部分时间都是空闲的。 -In general, the CPU can be doing other things while waiting for IO. It doesn't have to be disk IO. It can be network IO as well, or input from a user at the machine. Network and disk IO is often a lot slower than CPU's and memory IO. +一般来说,在CPU等待IO操作时可以处理其他任务。IO操作可以是磁盘IO,网络IO或者用户的输入。磁盘IO和网络IO远远慢于CPU IO和内存IO。 -Simpler Program Design +##Simpler Program Design If you were to program the above ordering of reading and processing by hand in a singlethreaded application, you would have to keep track of both the read and processing state of each file. Instead you can start two threads that each just reads and processes a single file. Each of these threads will be blocked while waiting for the disk to read its file. While waiting, other threads can use the CPU to process the parts of the file they have already read. The result is, that the disk is kept busy at all times, reading from various files into memory. This results in a better utilization of both the disk and the CPU. It is also easier to program, since each thread only has to keep track of a single file. -More responsive programs +##More responsive programs Another common goal for turning a singlethreaded application into a multithreaded application is to achieve a more responsive application. Imagine a server application that listens on some port for incoming requests. when a request is received, it handles the request and then goes back to listening. The server loop is sketched below: From 602bca8f596a4914c28f5a4b46017f51ea289348 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 15:55:20 +0800 Subject: [PATCH 064/524] Published with https://stackedit.io/ --- ...72\277\347\250\213\347\232\204\345\245\275\345\244\204.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" index a6ea4d9..87760e7 100644 --- "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" +++ "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" @@ -3,7 +3,7 @@ 尽管多线程带来的一些挑战,也让先写应用程序变得复杂,但它也带来了一系列好处: * 更好的资源利用率 -* 在某些情况下,让程序变得更加简单 +* 更简单的程序设计 * More responsive programs @@ -35,7 +35,7 @@ 一般来说,在CPU等待IO操作时可以处理其他任务。IO操作可以是磁盘IO,网络IO或者用户的输入。磁盘IO和网络IO远远慢于CPU IO和内存IO。 -##Simpler Program Design +##更简单的程序设计(Simpler Program Design) If you were to program the above ordering of reading and processing by hand in a singlethreaded application, you would have to keep track of both the read and processing state of each file. Instead you can start two threads that each just reads and processes a single file. Each of these threads will be blocked while waiting for the disk to read its file. While waiting, other threads can use the CPU to process the parts of the file they have already read. The result is, that the disk is kept busy at all times, reading from various files into memory. This results in a better utilization of both the disk and the CPU. It is also easier to program, since each thread only has to keep track of a single file. From 8fbb754b2387d980930d3e26f9149fa544de174b Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 16:00:31 +0800 Subject: [PATCH 065/524] Published with https://stackedit.io/ --- ...47\250\213\347\232\204\345\245\275\345\244\204.md" | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" index 87760e7..6c40b5c 100644 --- "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" +++ "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" @@ -43,11 +43,12 @@ If you were to program the above ordering of reading and processing by hand in a Another common goal for turning a singlethreaded application into a multithreaded application is to achieve a more responsive application. Imagine a server application that listens on some port for incoming requests. when a request is received, it handles the request and then goes back to listening. The server loop is sketched below: - - while(server is active){ - listen for request - process request - } +```Java +while(server is active){ + listen for request + process request +} +``` If the request takes a long time to process, no new clients can send requests to the server for that duration. Only while the server is listening can requests be received. An alternate design would be for the listening thread to pass the request to a worker thread, and return to listening immediatedly. The worker thread will process the request and send a reply to the client. This design is sketched below: From 1b20707681bfe7868df461593af7eb963e5d742e Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 16:36:53 +0800 Subject: [PATCH 066/524] Published with https://stackedit.io/ --- ...13\347\232\204\345\245\275\345\244\204.md" | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" index 6c40b5c..091c3bc 100644 --- "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" +++ "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" @@ -39,9 +39,9 @@ If you were to program the above ordering of reading and processing by hand in a singlethreaded application, you would have to keep track of both the read and processing state of each file. Instead you can start two threads that each just reads and processes a single file. Each of these threads will be blocked while waiting for the disk to read its file. While waiting, other threads can use the CPU to process the parts of the file they have already read. The result is, that the disk is kept busy at all times, reading from various files into memory. This results in a better utilization of both the disk and the CPU. It is also easier to program, since each thread only has to keep track of a single file. -##More responsive programs +##更具响应性的程序(More responsive programs) -Another common goal for turning a singlethreaded application into a multithreaded application is to achieve a more responsive application. Imagine a server application that listens on some port for incoming requests. when a request is received, it handles the request and then goes back to listening. The server loop is sketched below: +把单线程应用转化为多线程应用的另一个目标就是实现更具有响应性的应用程序。试想一下,监听某个端口请求的服务器应用程序,当请求到达时,应用程序进行处理,然后返回继续监听。代码如下: ```Java while(server is active){ @@ -49,15 +49,23 @@ while(server is active){ process request } ``` -If the request takes a long time to process, no new clients can send requests to the server for that duration. Only while the server is listening can requests be received. + +如果请求需要很长的处理时间,在这段期间内,应用程序不能处理后续的请求,只有当应用程序处理请求返回监听状态,才能继续接收请求。 + + An alternate design would be for the listening thread to pass the request to a worker thread, and return to listening immediatedly. The worker thread will process the request and send a reply to the client. This design is sketched below: +另一种设计是在监听线程将请求传递给工作线程,并返回到听immediatedly。工作线程将处理该请求并发送到客户端的回复。这种设计勾勒如下: + - while(server is active){ - listen for request + ```Java +while(server is active){ + listen for request hand request to worker thread - } +} +``` + This way the server thread will be back at listening sooner. Thus more clients can send requests to the server. The server has become more responsive. The same is true for desktop applications. If you click a button that starts a long task, and the thread executing the task is the thread updating the windows, buttons etc., then the application will appear unresponsive while the task executes. Instead the task can be handed off to a worker thread. While the worker thread is busy with the task, the window thread is free to respond to other user requests. When the worker thread is done it signals the window thread. The window thread can then update the application windows with the result of the task. The program with the worker thread design will appear more responsive to the user. From 5779b287321faaa5c2e8080c293fa347c4845059 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 16:43:38 +0800 Subject: [PATCH 067/524] Published with https://stackedit.io/ --- ...47\250\213\347\232\204\345\245\275\345\244\204.md" | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" index 091c3bc..75e5cce 100644 --- "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" +++ "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" @@ -41,7 +41,7 @@ If you were to program the above ordering of reading and processing by hand in a ##更具响应性的程序(More responsive programs) -把单线程应用转化为多线程应用的另一个目标就是实现更具有响应性的应用程序。试想一下,监听某个端口请求的服务器应用程序,当请求到达时,应用程序进行处理,然后返回继续监听。代码如下: +把单线程应用转化为多线程应用的另一个目标就是实现更具有响应性的应用程序。试想一下,监听某个端口请求的服务器应用程序,当请求到达时,应用程序进行处理,然后返回继续监听。程序设计勾勒如下: ```Java while(server is active){ @@ -52,12 +52,7 @@ while(server is active){ 如果请求需要很长的处理时间,在这段期间内,应用程序不能处理后续的请求,只有当应用程序处理请求返回监听状态,才能继续接收请求。 - - -An alternate design would be for the listening thread to pass the request to a worker thread, and return to listening immediatedly. The worker thread will process the request and send a reply to the client. This design is sketched below: - -另一种设计是在监听线程将请求传递给工作线程,并返回到听immediatedly。工作线程将处理该请求并发送到客户端的回复。这种设计勾勒如下: - +另一种设计就是监听线程接收请求,然后将请求传递给工作线程进行处理,并立即返回到监听状态。工作线程对请求进行处理,然后将结果响应给客户端。这种设计勾勒如下: ```Java while(server is active){ @@ -66,6 +61,8 @@ while(server is active){ } ``` + + This way the server thread will be back at listening sooner. Thus more clients can send requests to the server. The server has become more responsive. The same is true for desktop applications. If you click a button that starts a long task, and the thread executing the task is the thread updating the windows, buttons etc., then the application will appear unresponsive while the task executes. Instead the task can be handed off to a worker thread. While the worker thread is busy with the task, the window thread is free to respond to other user requests. When the worker thread is done it signals the window thread. The window thread can then update the application windows with the result of the task. The program with the worker thread design will appear more responsive to the user. From de60a2fdd17f3dab07947dd82dbe66e34b0f33a0 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 16:54:39 +0800 Subject: [PATCH 068/524] Published with https://stackedit.io/ --- ...2\277\347\250\213\347\232\204\345\245\275\345\244\204.md" | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" index 75e5cce..5389b28 100644 --- "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" +++ "b/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" @@ -61,9 +61,6 @@ while(server is active){ } ``` - - -This way the server thread will be back at listening sooner. Thus more clients can send requests to the server. The server has become more responsive. +在这种方式下,服务器线程将很快回到监听状态。因此,可以响应更多的用户请求。服务器变成更具有响应性。 The same is true for desktop applications. If you click a button that starts a long task, and the thread executing the task is the thread updating the windows, buttons etc., then the application will appear unresponsive while the task executes. Instead the task can be handed off to a worker thread. While the worker thread is busy with the task, the window thread is free to respond to other user requests. When the worker thread is done it signals the window thread. The window thread can then update the application windows with the result of the task. The program with the worker thread design will appear more responsive to the user. - From e0d1b469269ddb07500d8f8db83e965a394e6f0e Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 16:57:27 +0800 Subject: [PATCH 069/524] Published with https://stackedit.io/ --- ...72\277\347\250\213\347\232\204\346\210\220\346\234\254.md" | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 "Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" diff --git "a/Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" "b/Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" new file mode 100644 index 0000000..0a9de70 --- /dev/null +++ "b/Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" @@ -0,0 +1,4 @@ +#03.Multithreading Costs + + +> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file From f7b7a8d46bbc6b8728476602e6e28e99927d8e72 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 17:01:35 +0800 Subject: [PATCH 070/524] Published with https://stackedit.io/ --- ...13\347\232\204\346\210\220\346\234\254.md" | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" "b/Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" index 0a9de70..b83143f 100644 --- "a/Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" +++ "b/Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" @@ -1,4 +1,21 @@ -#03.Multithreading Costs +#03.多线程的代价 +Going from a singlethreaded to a multithreaded application doesn't just provide benefits. It also has some costs. Don't just multithread-enable an application just because you can. You should have a good idea that the benefits gained by doing so, are larger than the costs. When in doubt, try measuring the performance or responsiveness of the application, instead of just guessing. -> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file +##设计更加复杂(More complex design) + +Though some parts of a multithreaded applications is simpler than a singlethreaded application, other parts are more complex. Code executed by multiple threads accessing shared data need special attention. Thread interaction is far from always simple. Errors arising from incorrect thread synchronization can be very hard to detect, reproduce and fix. + +##上下文切换的开销(Context Switching Overhead) + +When a CPU switches from executing one thread to executing another, the CPU needs to save the local data, program pointer etc. of the current thread, and load the local data, program pointer etc. of the next thread to execute. This switch is called a "context switch". The CPU switches from executing in the context of one thread to executing in the context of another. + +Context switching isn't cheap. You don't want to switch between threads more than necessary. + +You can read more about context switching on Wikipedia: + +http://en.wikipedia.org/wiki/Context_switch + +##增加资源消耗(Increased Resource Consumption) + +A thread needs some resources from the computer in order to run. Besides CPU time a thread needs some memory to keep its local stack. It may also take up some resources inside the operating system needed to manage the thread. Try creating a program that creates 100 threads that does nothing but wait, and see how much memory the application takes when running. \ No newline at end of file From 3c90ba89e7f072b095382f868ad4c86f11e24178 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 17:04:28 +0800 Subject: [PATCH 071/524] Published with https://stackedit.io/ --- ...45\212\250Java\347\272\277\347\250\213.md" | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 "Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" new file mode 100644 index 0000000..f062cd7 --- /dev/null +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -0,0 +1,23 @@ +#04.创建和启动Java线程 + +Going from a singlethreaded to a multithreaded application doesn't just provide benefits. It also has some costs. Don't just multithread-enable an application just because you can. You should have a good idea that the benefits gained by doing so, are larger than the costs. When in doubt, try measuring the performance or responsiveness of the application, instead of just guessing. + +More complex design + +Though some parts of a multithreaded applications is simpler than a singlethreaded application, other parts are more complex. Code executed by multiple threads accessing shared data need special attention. Thread interaction is far from always simple. Errors arising from incorrect thread synchronization can be very hard to detect, reproduce and fix. + +Context Switching Overhead + +When a CPU switches from executing one thread to executing another, the CPU needs to save the local data, program pointer etc. of the current thread, and load the local data, program pointer etc. of the next thread to execute. This switch is called a "context switch". The CPU switches from executing in the context of one thread to executing in the context of another. + +Context switching isn't cheap. You don't want to switch between threads more than necessary. + +You can read more about context switching on Wikipedia: + +http://en.wikipedia.org/wiki/Context_switch + +Increased Resource Consumption + +A thread needs some resources from the computer in order to run. Besides CPU time a thread needs some memory to keep its local stack. It may also take up some resources inside the operating system needed to manage the thread. Try creating a program that creates 100 threads that does nothing but wait, and see how much memory the application takes when running. + +> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file From 8f87b5b2978ccffc9e44824ea563f62c3bde8412 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 17:07:52 +0800 Subject: [PATCH 072/524] Published with https://stackedit.io/ --- ...45\212\250Java\347\272\277\347\250\213.md" | 141 ++++++++++++++++-- 1 file changed, 130 insertions(+), 11 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index f062cd7..405c8bd 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -1,23 +1,142 @@ #04.创建和启动Java线程 -Going from a singlethreaded to a multithreaded application doesn't just provide benefits. It also has some costs. Don't just multithread-enable an application just because you can. You should have a good idea that the benefits gained by doing so, are larger than the costs. When in doubt, try measuring the performance or responsiveness of the application, instead of just guessing. +Java threads are objects like any other Java objects. Threads are instances of class java.lang.Thread, or instances of subclasses of this class. In addition to being objects, java threads can also execute code. -More complex design +##Creating and Starting Threads -Though some parts of a multithreaded applications is simpler than a singlethreaded application, other parts are more complex. Code executed by multiple threads accessing shared data need special attention. Thread interaction is far from always simple. Errors arising from incorrect thread synchronization can be very hard to detect, reproduce and fix. +Creating a thread in Java is done like this: -Context Switching Overhead + Thread thread = new Thread(); +To start the thread you will call its start() method, like this: -When a CPU switches from executing one thread to executing another, the CPU needs to save the local data, program pointer etc. of the current thread, and load the local data, program pointer etc. of the next thread to execute. This switch is called a "context switch". The CPU switches from executing in the context of one thread to executing in the context of another. + thread.start(); +This example doesn't specify any code for the thread to execute. It will stop again right away. -Context switching isn't cheap. You don't want to switch between threads more than necessary. +There are two ways to specify what code the thread should execute. The first is to create a subclass of Thread and override the run() method. The second method is to pass an object that implements Runnable to the Thread constructor. Both methods are covered below. -You can read more about context switching on Wikipedia: +##Thread Subclass -http://en.wikipedia.org/wiki/Context_switch +The first way to specify what code a thread is to run, is to create a subclass of Thread and override the run() method. The run() method is what is executed by the thread after you call start(). Here is an example: -Increased Resource Consumption + public class MyThread extends Thread { -A thread needs some resources from the computer in order to run. Besides CPU time a thread needs some memory to keep its local stack. It may also take up some resources inside the operating system needed to manage the thread. Try creating a program that creates 100 threads that does nothing but wait, and see how much memory the application takes when running. + public void run(){ + System.out.println("MyThread running"); + } + } +To create and start the above thread you can do like this: -> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file + MyThread myThread = new MyThread(); + myTread.start(); +The start() call will return as soon as the thread is started. It will not wait until the run() method is done. The run() method will execute as if executed by a different CPU. When the run() method executes it will print out the text "MyThread running". + +You can also create an anonymous subclass of Thread like this: + + Thread thread = new Thread(){ + public void run(){ + System.out.println("Thread Running"); + } + } + + thread.start(); +This example will print out the text "Thread running" once the run() method is executed by the new thread. + +##Runnable Interface Implemention + +The second way to specify what code a thread should run is by creating a class that implements java.lang.Runnable. The Runnable object can be executed by a Thread. + +Here is a Java Runnable example: + + public class MyRunnable implements Runnable { + + public void run(){ + System.out.println("MyRunnable running"); + } + } +To have the run() method executed by a thread, pass an instance of MyRunnable to a Thread in its constructor. Here is how that is done: + + Thread thread = new Thread(new MyRunnable()); + thread.start(); +When the thread is started it will call the run() method of the MyRunnable instance instead of executing it's own run() method. The above example would print out the text "MyRunnable running". + +You can also create an anonymous implementation of Runnable, like this: + + Runnable myRunnable = new Runnable(){ + + public void run(){ + System.out.println("Runnable running"); + } + } + + + Thread thread = new Thread(myRunnable); + thread.start(); +##Subclass or Runnable? + +There are no rules about which of the two methods that is the best. Both methods works. Personally though, I prefer implementing Runnable, and handing an instance of the implementation to a Thread instance. When having the Runnable's executed by a thread pool it is easy to queue up the Runnable instances until a thread from the pool is idle. This is a little harder to do with Thread subclasses. + +Sometimes you may have to implement Runnable as well as subclass Thread. For instance, if creating a subclass of Thread that can execute more than one Runnable. This is typically the case when implementing a thread pool. + +##Common Pitfall: Calling run() instead of start() + +When creating and starting a thread a common mistake is to call the run() method of the Thread instead of start(), like this: + + Thread newThread = new Thread(MyRunnable()); + thread.run(); //should be start(); +At first you may not notice anything because the Runnable's run() method is executed like you expected. However, it is NOT executed by the new thread you just created. Instead the run() method is executed by the thread that created the thread. In other words, the thread that executed the above two lines of code. To have the run() method of the MyRunnable instance called by the new created thread, newThread, you MUST call the newThread.start() method. + +##Thread Names + +When you create a thread you can give it a name. The name can help you distinguish different threads from each other. For instance, if multiple threads write to System.out it can be handy to see which thread wrote the text. Here is an example: + +```Java +Thread thread = new Thread("New Thread") { + public void run(){ + System.out.println("run by: " + getname()); + } +}; + +thread.start(); +System.out.println(thread.getName()); +``` + +Notice the string "New Thread" passed as parameter to the Thread constructor. This string is the name of the thread. The name can be obtained by the Thread's getName() method. You can also pass a name to a Thread when using a Runnable implementation. Here is how that looks: + +```Java +MyRunnable runnable = new MyRunnable(); +Thread thread = new Thread(runnable, "New Thread"); + +thread.start(); +System.out.println(thread.getName()); +``` +Notice however, that since the MyRunnable class is not a subclass of Thread, it does not have access to the getName() method of the thread executing it. A reference to the currently executing thread can be obtained using the call + +```Java + Thread.currentThread(); +``` +Getting the name of the thread currently executing the code can therefore be done like this: + +```Java +String threadName = Thread.currentThread().getName(); +``` +##Java Thread Example + +Here is a small example. First it prints out the name of the thread executing the main() method. This thread is assigned by the JVM. Then it starts up 10 threads and give them all a number as name ("" + i). Each thread then prints its name out, and then stops executing. + +```Java +public class ThreadExample { + + public static void main(String[] args){ + System.out.println(Thread.currentThread().getName()); + for(int i=0; i<10; i++){ + new Thread("" + i){ + public void run(){ + System.out.println("Thread: " + getName() + " running"); + } + }.start(); + } + } +} +``` + +Note that even if the threads are started in sequence (1, 2, 3 etc.) they may not execute sequentially, meaning thread 1 may not be the first thread to write its name to System.out. This is because the threads are in principle executing in parallel and not sequentially. The JVM and/or operating system determines the order in which the threads are executed. This order does not have to be the same order in which they were started. \ No newline at end of file From d17458f85f6dd4a090f3bbcfa536f9716c80fb9a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 5 Sep 2014 17:13:32 +0800 Subject: [PATCH 073/524] Published with https://stackedit.io/ --- ...257\345\212\250Java\347\272\277\347\250\213.md" | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index 405c8bd..ce8b191 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -2,7 +2,7 @@ Java threads are objects like any other Java objects. Threads are instances of class java.lang.Thread, or instances of subclasses of this class. In addition to being objects, java threads can also execute code. -##Creating and Starting Threads +##创建和启动线程(Creating and Starting Threads) Creating a thread in Java is done like this: @@ -14,7 +14,7 @@ This example doesn't specify any code for the thread to execute. It will stop ag There are two ways to specify what code the thread should execute. The first is to create a subclass of Thread and override the run() method. The second method is to pass an object that implements Runnable to the Thread constructor. Both methods are covered below. -##Thread Subclass +##继承Thread类(Thread Subclass) The first way to specify what code a thread is to run, is to create a subclass of Thread and override the run() method. The run() method is what is executed by the thread after you call start(). Here is an example: @@ -41,7 +41,7 @@ You can also create an anonymous subclass of Thread like this: thread.start(); This example will print out the text "Thread running" once the run() method is executed by the new thread. -##Runnable Interface Implemention +##实现Runnable接口(Runnable Interface Implemention) The second way to specify what code a thread should run is by creating a class that implements java.lang.Runnable. The Runnable object can be executed by a Thread. @@ -71,13 +71,13 @@ You can also create an anonymous implementation of Runnable, like this: Thread thread = new Thread(myRunnable); thread.start(); -##Subclass or Runnable? +##子类还是实现接口(Subclass or Runnable)? There are no rules about which of the two methods that is the best. Both methods works. Personally though, I prefer implementing Runnable, and handing an instance of the implementation to a Thread instance. When having the Runnable's executed by a thread pool it is easy to queue up the Runnable instances until a thread from the pool is idle. This is a little harder to do with Thread subclasses. Sometimes you may have to implement Runnable as well as subclass Thread. For instance, if creating a subclass of Thread that can execute more than one Runnable. This is typically the case when implementing a thread pool. -##Common Pitfall: Calling run() instead of start() +##常见陷阱:(Common Pitfall: Calling run() instead of start()) When creating and starting a thread a common mistake is to call the run() method of the Thread instead of start(), like this: @@ -85,7 +85,7 @@ When creating and starting a thread a common mistake is to call the run() method thread.run(); //should be start(); At first you may not notice anything because the Runnable's run() method is executed like you expected. However, it is NOT executed by the new thread you just created. Instead the run() method is executed by the thread that created the thread. In other words, the thread that executed the above two lines of code. To have the run() method of the MyRunnable instance called by the new created thread, newThread, you MUST call the newThread.start() method. -##Thread Names +##线程名称(Thread Names) When you create a thread you can give it a name. The name can help you distinguish different threads from each other. For instance, if multiple threads write to System.out it can be handy to see which thread wrote the text. Here is an example: @@ -119,7 +119,7 @@ Getting the name of the thread currently executing the code can therefore be don ```Java String threadName = Thread.currentThread().getName(); ``` -##Java Thread Example +##Java线程示例(Java Thread Example) Here is a small example. First it prints out the name of the thread executing the main() method. This thread is assigned by the JVM. Then it starts up 10 threads and give them all a number as name ("" + i). Each thread then prints its name out, and then stops executing. From 1ffc98f84d46da7e4d7d14a539594a71600fe1ef Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 14:46:09 +0800 Subject: [PATCH 074/524] Published with https://stackedit.io/ --- ....Java NIO\347\274\223\345\206\262\345\214\272.md" | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index aa19fa8..228152c 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -13,7 +13,7 @@ Java NIO中的**缓冲区(Buffers)**用于跟**通道(Channels)**交互 * 从缓冲区中读取数据; * 调用buffer.clear()或buffer.compact()方法。 -当你往缓冲区写入数据的时候,缓冲区会跟踪记录你写入的数据量。当你需要缓冲区读取数据时,你需要调用`flip()`方法将缓冲区从**写入模式**切换为**读取模式**。在读取模式中,你可以读取之前往缓冲区写入的所有数据。 +当你往缓冲区写入数据的时候,缓冲区会跟踪记录你写入的数据量。当你需要缓冲区读取数据时,你需要调用`flip()`方法将缓冲区从**写模式**切换为**读模式**。在读模式中,你可以读取之前往缓冲区写入的所有数据。 当你读取完数据之后,你需要清空缓冲区,以便可以写入数据。你可以通过两种方式来完成:调用`clear()`或`compact()`方法。__`clear()`方法会清空整个缓冲区的数据。而`compact()`方法只会清空已经读取过的数据,尚未读取过的数据会被移动到缓冲区的前端,以便下次继续读取。__ @@ -52,9 +52,9 @@ aFile.close(); * 极限(Limit) -**position**和**limit**在读取模式/写入模式中具有不同的含义。而**capacity**在任何情况都具有同一含义:**缓冲区的容量大小。** +**position**和**limit**在读模式/写模式中具有不同的含义。而**capacity**在任何情况都具有同一含义:**缓冲区的容量大小。** -下面这个图描绘了capacity,position和limit在读取模式和写入模式中的含义: +下面这个图描绘了capacity,position和limit在读模式和写模式中的含义:  @@ -66,13 +66,13 @@ aFile.close(); 当你往缓冲区写入数据时,实际上你是往缓冲区中的指定的位置写入数据。这个位置初始值为0,当往缓冲区写入数据时,position会指向下一个可写入的内存单元。postion的最大值为capacity-1。 -当你从缓冲区读取数据时,你同样的是从position指定的位置读取数据。当你调用`flip()`方法使缓冲区由**写入模式**切换成**读取模式**后,position会重置为0。当从position指定单元读数据后,postion会移至下一个可读取单元。 +当你从缓冲区读取数据时,你同样的是从position指定的位置读取数据。当你调用`flip()`方法使缓冲区由**写模式**切换成**读模式**后,position会重置为0。当从position指定单元读数据后,postion会移至下一个可读取单元。 ###Limit -在**写入模式**中,limit指定的是能写入数据量的大小。在写入模式中,limit的值等于capacity的值。 +在**写模式**中,limit指定的是能写入数据量的大小。在写模式中,limit的值等于capacity的值。 -当调用`flip()`方法使缓冲区切换成**读取模式**后,limit会重置为你能读取的数据量的大小。因此,在调用`flip()`方法后,limit重置为position的值,而position重置为0。 +当调用`flip()`方法使缓冲区切换成**读模式**后,limit会重置为你能读取的数据量的大小。因此,在调用`flip()`方法后,limit重置为position的值,而position重置为0。 ##Buffer Types From f5dba080abd6db0c3739e2f2d25faa2baf9d4310 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 15:25:34 +0800 Subject: [PATCH 075/524] Published with https://stackedit.io/ --- ...IO\347\274\223\345\206\262\345\214\272.md" | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index 228152c..2c0b095 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -123,43 +123,44 @@ buf.put(127); ###flip() -The flip() method switches a Buffer from writing mode to reading mode. Calling flip() sets the position back to 0, and sets the limit to where position just was. +调用`flip()`方法可以将缓冲区区从写模式切换为模式,此时limit被重置为position的值,而position被重置为0。 -In other words, position now marks the reading position, and limit marks how many bytes, chars etc. were written into the buffer - the limit of how many bytes, chars etc. that can be read. +换句话说,position标识当前读的位置,而limit标识缓存区可读内容的大小。 -Reading Data from a Buffer +##从缓冲区读取数据(Reading Data from a Buffer) -There are two ways you can read data from a Buffer. +从缓冲区读取数据有两种方式: -Read data from the buffer into a channel. -Read data from the buffer yourself, using one of the get() methods. -Here is an example of how you can read data from a buffer into a channel: +* 从缓冲区读取数据到通道中。 +* 直接调用缓冲区的`get()`方法。 + +以下是这两种方法对应的代码: ```Java //read from buffer into channel. int bytesWritten = inChannel.write(buf); -Here is an example that reads data from a Buffer using the get() method: +``` +```Java byte aByte = buf.get(); ``` -There are many other versions of the get() method, allowing you to read data from the Buffer in many different ways. For instance, reading at specific positions, or reading an array of bytes from the buffer. See the JavaDoc for the concrete buffer implementation for more details. +Java API提供了多种重载的`get()`方法。详情请查阅文档。 ###rewind() -The Buffer.rewind() sets the position back to 0, so you can reread all the data in the buffer. The limit remains untouched, thus still marking how many elements (bytes, chars etc.) that can be read from the Buffer. +`Buffer.rewind()`可以将**position**重置为0,这样你就可以多次读取缓冲区的数据,期间**limit**的值保持不边 ###clear() and compact() -Once you are done reading data out of the Buffer you have to make the Buffer ready for writing again. You can do so either by calling clear() or by calling compact(). +当从缓冲区读取完数据后,可以调用`clear()`或`compact()`将缓冲区切换为写模式。 -If you call clear() the position is set back to 0 and the limit to capacity. In other words, the Buffer is cleared. The data in the Buffer is not cleared. Only the markers telling where you can write data into the Buffer are. +如果调用的是`clear()`方法,position重置为0,limit重置为capacity的值。换言之,缓冲区被清除了,但实际上缓冲区的数据并没被清除。 -If there is any unread data in the Buffer when you call clear() that data will be "forgotten", meaning you no longer have any markers telling what data has been read, and what has not been read. +如果缓冲区中还有需要读取的数据,同时你需要清除已经读取过的数据,这时你可以调用`compact()`方法。 -If there is still unread data in the Buffer, and you want to read it later, but you need to do some writing first, call compact() instead of clear(). +`compact()`方法会复制尚未读取的数据到缓冲区的前面,然后将position设置为未读取数据的最后一个元素的后一位,而limit重置为capacity的值。这样就可以保证未读取的数据不会丢失,同时又可以继续写入数据。 -compact() copies all unread data to the beginning of the Buffer. Then it sets position to right after the last unread element. The limit property is still set to capacity, just like clear() does. Now the Buffer is ready for writing, but you will not overwrite the unread data. ###mark() and reset() @@ -167,7 +168,6 @@ You can mark a given position in a Buffer by calling the Buffer.mark() method. Y ```Java buffer.mark(); - //call buffer.get() a couple of times, e.g. during parsing. buffer.reset(); //set position back to mark. From 471a3377989fc40cc642cb9a24bcc66b3fa1d68c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 15:31:29 +0800 Subject: [PATCH 076/524] Published with https://stackedit.io/ --- .../04.Java NIO\347\274\223\345\206\262\345\214\272.md" | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index 2c0b095..7ad3dea 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -162,18 +162,19 @@ Java API提供了多种重载的`get()`方法。详情请查阅文档。 `compact()`方法会复制尚未读取的数据到缓冲区的前面,然后将position设置为未读取数据的最后一个元素的后一位,而limit重置为capacity的值。这样就可以保证未读取的数据不会丢失,同时又可以继续写入数据。 -###mark() and reset() +###mark()和reset() -You can mark a given position in a Buffer by calling the Buffer.mark() method. You can then later reset the position back to the marked position by calling the Buffer.reset() method. Here is an example: +`Buffer.mark()`可以对position的位置进行标志,在进行一系列操作后,可以调用`reset()`将position重置为`Buffer.mark()`标志的位置。例子: ```Java buffer.mark(); //call buffer.get() a couple of times, e.g. during parsing. buffer.reset(); //set position back to mark. -equals() and compareTo() ``` +##equals()和compareTo() + It is possible to compare two buffers using equals() and compareTo(). ###equals() From f62c37e6a2da684449054a66e62a047509212046 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 15:43:10 +0800 Subject: [PATCH 077/524] Published with https://stackedit.io/ --- ...IO\347\274\223\345\206\262\345\214\272.md" | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index 7ad3dea..2b487a4 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -175,18 +175,21 @@ buffer.reset(); //set position back to mark. ##equals()和compareTo() -It is possible to compare two buffers using equals() and compareTo(). -###equals() +可以调用缓冲区的`equals()`方法和`compareTo()`方法对缓冲区进行比较。 -Two buffers are equal if: +####equals() -They are of the same type (byte, char, int etc.) -They have the same amount of remaining bytes, chars etc. in the buffer. -All remaining bytes, chars etc. are equal. -As you can see, equals only compares part of the Buffer, not every single element inside it. In fact, it just compares the remaining elements in the Buffer. +如果符合以下情况,则两个缓冲区的`equals()`返回值为true: + +* 缓冲区的类型相同(byte、char等等); +* 缓冲区中有效数据的数据量相等; +* 缓冲区中有效数据的数据一致; + +如上所示,如果缓冲区中的**有效数据**都相同,则`equals()`返回值为true。 + +####compareTo() -###compareTo() The compareTo() method compares the remaining elements (bytes, chars etc.) of the two buffers, for use in e.g. sorting routines. A buffer is considered "smaller" than another buffer if: From 9fa5a81cbf05583e849b7939b5bedfcba1b1a105 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 15:46:31 +0800 Subject: [PATCH 078/524] Published with https://stackedit.io/ --- "Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" | 1 - 1 file changed, 1 deletion(-) diff --git "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" index 2b487a4..3b33ef3 100644 --- "a/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" +++ "b/Java-NIO/04.Java NIO\347\274\223\345\206\262\345\214\272.md" @@ -190,7 +190,6 @@ buffer.reset(); //set position back to mark. ####compareTo() - The compareTo() method compares the remaining elements (bytes, chars etc.) of the two buffers, for use in e.g. sorting routines. A buffer is considered "smaller" than another buffer if: The first element which is equal to the corresponding element in the other buffer, is smaller than that in the other buffer. From 5c38890957c7e4e426982c62520977146217fa15 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 16:47:18 +0800 Subject: [PATCH 079/524] Published with https://stackedit.io/ --- ...45\212\250Java\347\272\277\347\250\213.md" | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index ce8b191..3063bb3 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -1,18 +1,24 @@ #04.创建和启动Java线程 -Java threads are objects like any other Java objects. Threads are instances of class java.lang.Thread, or instances of subclasses of this class. In addition to being objects, java threads can also execute code. +Java线程对象与其它的对象相似。线程对象是`java.lang.Thread`的实例,或是`java.lang.Thread`的子类的实例。跟普通对象不同,线程对象可以执行代码。 ##创建和启动线程(Creating and Starting Threads) -Creating a thread in Java is done like this: +在Java中,可以使用以下方式创建线程: - Thread thread = new Thread(); -To start the thread you will call its start() method, like this: +```Java +Thread thread = new Thread(); +``` - thread.start(); -This example doesn't specify any code for the thread to execute. It will stop again right away. +调用`Thread.start()`可以启动线程: + +```Java +thread.start(); +``` + +这个例子并没有为线程指定要执行的代码,所以它会很快返回并停止。 -There are two ways to specify what code the thread should execute. The first is to create a subclass of Thread and override the run() method. The second method is to pass an object that implements Runnable to the Thread constructor. Both methods are covered below. +有两种方法可以为线程指定需要执行的代码。第一种方式是创建`Thread`的子类并重写`run()`方法;第二种方式是将实现`Runnable`接口的对象作为构造参数传给`Thread(Runnale r)`。 ##继承Thread类(Thread Subclass) @@ -71,6 +77,8 @@ You can also create an anonymous implementation of Runnable, like this: Thread thread = new Thread(myRunnable); thread.start(); + + ##子类还是实现接口(Subclass or Runnable)? There are no rules about which of the two methods that is the best. Both methods works. Personally though, I prefer implementing Runnable, and handing an instance of the implementation to a Thread instance. When having the Runnable's executed by a thread pool it is easy to queue up the Runnable instances until a thread from the pool is idle. This is a little harder to do with Thread subclasses. From 469801ccdebde1291fac7791640d441c217eb2ed Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 16:56:12 +0800 Subject: [PATCH 080/524] Published with https://stackedit.io/ --- ...45\212\250Java\347\272\277\347\250\213.md" | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index 3063bb3..2d71904 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -22,18 +22,24 @@ thread.start(); ##继承Thread类(Thread Subclass) -The first way to specify what code a thread is to run, is to create a subclass of Thread and override the run() method. The run() method is what is executed by the thread after you call start(). Here is an example: +第一种为线程指定执行代码的方法:**继承Thread类并重写run方法。** `run()`方法在调用`Thread.start()`后执行。例子: - public class MyThread extends Thread { - - public void run(){ - System.out.println("MyThread running"); - } +```Java +public class MyThread extends Thread { + public void run(){ + System.out.println("MyThread running"); } -To create and start the above thread you can do like this: +} +``` +通过下面的代码创建并执行线程: + +``` MyThread myThread = new MyThread(); myTread.start(); +``` + + The start() call will return as soon as the thread is started. It will not wait until the run() method is done. The run() method will execute as if executed by a different CPU. When the run() method executes it will print out the text "MyThread running". You can also create an anonymous subclass of Thread like this: From 9abf9783ae7b4fb3c2bec77730e0356eaf1aea95 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 17:05:12 +0800 Subject: [PATCH 081/524] Published with https://stackedit.io/ --- ...214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index 2d71904..08bb129 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -39,8 +39,9 @@ public class MyThread extends Thread { myTread.start(); ``` +`start()`方法的调用会立即返回,并不会等待`run()`方法的执行,就好像这段代码被其他的CPU执行一样。 + -The start() call will return as soon as the thread is started. It will not wait until the run() method is done. The run() method will execute as if executed by a different CPU. When the run() method executes it will print out the text "MyThread running". You can also create an anonymous subclass of Thread like this: From 5cce351a3aa34e2ceb57a0ba1759e78497ecf698 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 17:33:00 +0800 Subject: [PATCH 082/524] Published with https://stackedit.io/ --- ...\345\212\250Java\347\272\277\347\250\213.md" | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index 08bb129..95e1233 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -41,18 +41,17 @@ public class MyThread extends Thread { `start()`方法的调用会立即返回,并不会等待`run()`方法的执行,就好像这段代码被其他的CPU执行一样。 +你还可以使用匿名子类来创建线程对象: - -You can also create an anonymous subclass of Thread like this: - - Thread thread = new Thread(){ - public void run(){ - System.out.println("Thread Running"); - } +```Java +Thread thread = new Thread(){ + public void run(){ + System.out.println("Thread Running"); } +} - thread.start(); -This example will print out the text "Thread running" once the run() method is executed by the new thread. +thread.start(); +``` ##实现Runnable接口(Runnable Interface Implemention) From 99779f8c133ea32db9b6fcb09ce7405e9ebdb6e1 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 17:40:50 +0800 Subject: [PATCH 083/524] Published with https://stackedit.io/ --- ...45\212\250Java\347\272\277\347\250\213.md" | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index 95e1233..ee4d150 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -55,20 +55,26 @@ thread.start(); ##实现Runnable接口(Runnable Interface Implemention) -The second way to specify what code a thread should run is by creating a class that implements java.lang.Runnable. The Runnable object can be executed by a Thread. +第二种为线程指定执行代码的方法:创建实现`java.lang.Runnable`接口的对象,然后把该对象交给Thread执行。 -Here is a Java Runnable example: +MyRunnable类实现Runnable接口: - public class MyRunnable implements Runnable { - - public void run(){ - System.out.println("MyRunnable running"); - } +```Java +public class MyRunnable implements Runnable { + public void run(){ + System.out.println("MyRunnable running"); } -To have the run() method executed by a thread, pass an instance of MyRunnable to a Thread in its constructor. Here is how that is done: +} +``` + +将MyRunnable的实例作为构造参数传给Thread,然后通过`thread.start()`启动线程: + +```Java +Thread thread = new Thread(new MyRunnable()); +thread.start(); +``` + - Thread thread = new Thread(new MyRunnable()); - thread.start(); When the thread is started it will call the run() method of the MyRunnable instance instead of executing it's own run() method. The above example would print out the text "MyRunnable running". You can also create an anonymous implementation of Runnable, like this: From caf284a83ae4b12db6964a6e750ba997835873dd Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 17:46:15 +0800 Subject: [PATCH 084/524] Published with https://stackedit.io/ --- ...45\212\250Java\347\272\277\347\250\213.md" | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index ee4d150..60757b3 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -74,22 +74,22 @@ Thread thread = new Thread(new MyRunnable()); thread.start(); ``` +当线程启动后,它会调用MyRunnable实例的`run()` 方法而不是自身的`run()`方法。 -When the thread is started it will call the run() method of the MyRunnable instance instead of executing it's own run() method. The above example would print out the text "MyRunnable running". -You can also create an anonymous implementation of Runnable, like this: +同样,你可以通过匿名Runnable类来实现: - Runnable myRunnable = new Runnable(){ +````Java +Runnable myRunnable = new Runnable(){ - public void run(){ - System.out.println("Runnable running"); - } - } - - - Thread thread = new Thread(myRunnable); - thread.start(); + public void run(){ + System.out.println("Runnable running"); + } +} +Thread thread = new Thread(myRunnable); +thread.start(); +``` ##子类还是实现接口(Subclass or Runnable)? From fe9c8a0b525a5907e87a2ecfcd4a3b54a7e0cf2c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 18:17:37 +0800 Subject: [PATCH 085/524] Published with https://stackedit.io/ --- ...220\257\345\212\250Java\347\272\277\347\250\213.md" | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index 60757b3..ad798ef 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -101,8 +101,11 @@ Sometimes you may have to implement Runnable as well as subclass Thread. For ins When creating and starting a thread a common mistake is to call the run() method of the Thread instead of start(), like this: - Thread newThread = new Thread(MyRunnable()); - thread.run(); //should be start(); +```Java +Thread newThread = new Thread(MyRunnable()); +thread.run(); //should be start(); +``` + At first you may not notice anything because the Runnable's run() method is executed like you expected. However, it is NOT executed by the new thread you just created. Instead the run() method is executed by the thread that created the thread. In other words, the thread that executed the above two lines of code. To have the run() method of the MyRunnable instance called by the new created thread, newThread, you MUST call the newThread.start() method. ##线程名称(Thread Names) @@ -132,8 +135,9 @@ System.out.println(thread.getName()); Notice however, that since the MyRunnable class is not a subclass of Thread, it does not have access to the getName() method of the thread executing it. A reference to the currently executing thread can be obtained using the call ```Java - Thread.currentThread(); +Thread.currentThread(); ``` + Getting the name of the thread currently executing the code can therefore be done like this: ```Java From 0bec5fe542bdbee95f82b20888de6b6e8bddfa84 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 18:35:29 +0800 Subject: [PATCH 086/524] Published with https://stackedit.io/ --- ...\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index ad798ef..2c90910 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -95,7 +95,7 @@ thread.start(); There are no rules about which of the two methods that is the best. Both methods works. Personally though, I prefer implementing Runnable, and handing an instance of the implementation to a Thread instance. When having the Runnable's executed by a thread pool it is easy to queue up the Runnable instances until a thread from the pool is idle. This is a little harder to do with Thread subclasses. -Sometimes you may have to implement Runnable as well as subclass Thread. For instance, if creating a subclass of Thread that can execute more than one Runnable. This is typically the case when implementing a thread pool. +Sometimes you may have to implement Runnable as well as subclass Thread. For instance, if creating a subclass of Thread that can execute more than one Runnable. This is typically the case when implementing a thread pool. ??? Thread本身已经实现Runnable接口,这段话如何理解?? ##常见陷阱:(Common Pitfall: Calling run() instead of start()) From 6ec83c94a3f68ff223a2d7bb8099d6aad06896c9 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 18:38:23 +0800 Subject: [PATCH 087/524] Published with https://stackedit.io/ --- ...14\345\220\257\345\212\250Java\347\272\277\347\250\213.md" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index 2c90910..d17014a 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -99,13 +99,15 @@ Sometimes you may have to implement Runnable as well as subclass Thread. For ins ##常见陷阱:(Common Pitfall: Calling run() instead of start()) -When creating and starting a thread a common mistake is to call the run() method of the Thread instead of start(), like this: +一个常见的陷阱就是调用`run()`方法来启动线程: ```Java Thread newThread = new Thread(MyRunnable()); thread.run(); //should be start(); ``` + + At first you may not notice anything because the Runnable's run() method is executed like you expected. However, it is NOT executed by the new thread you just created. Instead the run() method is executed by the thread that created the thread. In other words, the thread that executed the above two lines of code. To have the run() method of the MyRunnable instance called by the new created thread, newThread, you MUST call the newThread.start() method. ##线程名称(Thread Names) From 236ccce5168ab18cea75ae73ba7dbb27fab1fe6d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 9 Sep 2014 18:42:17 +0800 Subject: [PATCH 088/524] Published with https://stackedit.io/ --- ...214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index d17014a..d4b7ffe 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -106,10 +106,9 @@ Thread newThread = new Thread(MyRunnable()); thread.run(); //should be start(); ``` +这段代码的`run()`会正常执行,然而,它并不是由新创建的线程执行的,而是由当前线程执行。如果要创建新的线程来执行,必须调用`start()`方法而不是`run()`方法。 -At first you may not notice anything because the Runnable's run() method is executed like you expected. However, it is NOT executed by the new thread you just created. Instead the run() method is executed by the thread that created the thread. In other words, the thread that executed the above two lines of code. To have the run() method of the MyRunnable instance called by the new created thread, newThread, you MUST call the newThread.start() method. - ##线程名称(Thread Names) When you create a thread you can give it a name. The name can help you distinguish different threads from each other. For instance, if multiple threads write to System.out it can be handy to see which thread wrote the text. Here is an example: From 536d277151b59bd47d17d88331860cb55f4c1160 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 14:52:29 +0800 Subject: [PATCH 089/524] Published with https://stackedit.io/ --- ...5\220\257\345\212\250Java\347\272\277\347\250\213.md" | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index d4b7ffe..c8901da 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -111,8 +111,8 @@ thread.run(); //should be start(); ##线程名称(Thread Names) -When you create a thread you can give it a name. The name can help you distinguish different threads from each other. For instance, if multiple threads write to System.out it can be handy to see which thread wrote the text. Here is an example: - + 当创建线程时,可以对线程命名,通过对线程命名可以用来区分不同的线程。举个例子,有多个线程通过`System.out`写内容到控制台,那么可以通过名字很方便地区分不同的线程: + ```Java Thread thread = new Thread("New Thread") { public void run(){ @@ -123,8 +123,7 @@ Thread thread = new Thread("New Thread") { thread.start(); System.out.println(thread.getName()); ``` - -Notice the string "New Thread" passed as parameter to the Thread constructor. This string is the name of the thread. The name can be obtained by the Thread's getName() method. You can also pass a name to a Thread when using a Runnable implementation. Here is how that looks: +字符串“New Thread”通过构造函数传给Thread,这个就是线程的名字。可以通过`getName()`获取线程的名字。使用Runnable接口时,可以通过如下方式进行命名: ```Java MyRunnable runnable = new MyRunnable(); @@ -133,6 +132,8 @@ Thread thread = new Thread(runnable, "New Thread"); thread.start(); System.out.println(thread.getName()); ``` + + Notice however, that since the MyRunnable class is not a subclass of Thread, it does not have access to the getName() method of the thread executing it. A reference to the currently executing thread can be obtained using the call ```Java From 096d2f27e019d4d5e27caef0bd13a92da2516832 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 14:57:13 +0800 Subject: [PATCH 090/524] Published with https://stackedit.io/ --- ...5\220\257\345\212\250Java\347\272\277\347\250\213.md" | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index c8901da..990b7b1 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -133,14 +133,7 @@ thread.start(); System.out.println(thread.getName()); ``` - -Notice however, that since the MyRunnable class is not a subclass of Thread, it does not have access to the getName() method of the thread executing it. A reference to the currently executing thread can be obtained using the call - -```Java -Thread.currentThread(); -``` - -Getting the name of the thread currently executing the code can therefore be done like this: +获取当前线程的名字,可以通过一下方式获取: ```Java String threadName = Thread.currentThread().getName(); From c8be56e57ac7957e4363802a6d264a875981430b Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 15:10:42 +0800 Subject: [PATCH 091/524] Published with https://stackedit.io/ --- ...14\345\220\257\345\212\250Java\347\272\277\347\250\213.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" index 990b7b1..efcec90 100644 --- "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" +++ "b/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" @@ -140,7 +140,7 @@ String threadName = Thread.currentThread().getName(); ``` ##Java线程示例(Java Thread Example) -Here is a small example. First it prints out the name of the thread executing the main() method. This thread is assigned by the JVM. Then it starts up 10 threads and give them all a number as name ("" + i). Each thread then prints its name out, and then stops executing. +下面的线程例子。首先打印执行main方法线程的名字(这个线程由JVM分配)。然后启动10个线程,并递增赋予它们名字i,每个线程打印自己的名字,最后停止: ```Java public class ThreadExample { @@ -158,4 +158,4 @@ public class ThreadExample { } ``` -Note that even if the threads are started in sequence (1, 2, 3 etc.) they may not execute sequentially, meaning thread 1 may not be the first thread to write its name to System.out. This is because the threads are in principle executing in parallel and not sequentially. The JVM and/or operating system determines the order in which the threads are executed. This order does not have to be the same order in which they were started. \ No newline at end of file +值得注意的是,虽然线程是依次按1,2,3启动,但是它们的执行却不是顺序的,也就说第一个启动的线程,并不一定第一个打印输出。这是因为线程**原则上**是并行执行而不是顺序执行,由JVM或操作系统来决定线程的执行顺序,这个顺序并不需要与它们的启动顺序一致。 \ No newline at end of file From 69a639d4df073f99930828971161f89ad31d16f0 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 16:30:17 +0800 Subject: [PATCH 092/524] Published with https://stackedit.io/ --- ...14\344\270\264\347\225\214\345\214\272.md" | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 "\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" diff --git "a/\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" "b/\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" new file mode 100644 index 0000000..0ad642b --- /dev/null +++ "b/\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" @@ -0,0 +1,43 @@ + +#资源竞争和临界区(Race Conditions and Critical Sections) + +Running more than one thread inside the same application does not by itself cause problems. The problems arise when multiple threads access the same resources. For instance the same memory (variables, arrays, or objects), systems (databases, web services etc.) or files. In fact, problems only arise if one or more of the threads write to these resources. It is safe to let multiple threads read the same resources, as long as the resources do not change. + +Here is a code example that may fail if executed by multiple threads simultaneously: + +``` +public class Counter { + + protected long count = 0; + + public void add(long value){ + this.count = this.count + value; + } +} +``` +Imagine if two threads, A and B, are executing the add method on the same instance of the Counter class. There is no way to know when the operating system switches between the two threads. The code is not executed as a single instruction by the Java virtual machine. Rather it is executed along the lines of: + +``` +get this.count from memory into register +add value to register +write register to memory +``` + +Observe what happens with the following mixed execution of threads A and B: + +``` +this.count = 0; +A: reads this.count into a register (0) +B: reads this.count into a register (0) +B: adds value 2 to register +B: writes register value (2) back to memory. this.count now equals 2 +A: adds value 3 to register +A: writes register value (3) back to memory. this.count now equals 3 + ``` + +The two threads added the values 2 and 3 to the counter. Thus the value should have been 5 after the two threads complete execution. However, since the execution of the two threads is interleaved, both threads read the value 0 from memory. Then they add their individual values, 2 and 3, to the value, and write the result back to memory. Instead of 5, the value left in this.count will be the value written by the last thread to write its value. In the above case it is thread A, but it could as well have been thread B. Without proper thread synchronization mechanisms there is no way to know exactly how the thread execution is interleaved. + +## Race Conditions & Critical Sections + +The situation where two threads compete for the same resource, where the sequence in which the resource is accessed is significant, is called race conditions. A code section that leads to race conditions is called a critical section. In the previous example the method add() is a critical section, leading to race conditions. Race conditions can be avoided by proper thread synchronization in critical sections. + From 6040c4954144f16e2d152eeca0504fda23af646e Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 16:32:29 +0800 Subject: [PATCH 093/524] Published with https://stackedit.io/ --- ...14\344\270\264\347\225\214\345\214\272.md" | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 "Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" diff --git "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" new file mode 100644 index 0000000..0ad642b --- /dev/null +++ "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" @@ -0,0 +1,43 @@ + +#资源竞争和临界区(Race Conditions and Critical Sections) + +Running more than one thread inside the same application does not by itself cause problems. The problems arise when multiple threads access the same resources. For instance the same memory (variables, arrays, or objects), systems (databases, web services etc.) or files. In fact, problems only arise if one or more of the threads write to these resources. It is safe to let multiple threads read the same resources, as long as the resources do not change. + +Here is a code example that may fail if executed by multiple threads simultaneously: + +``` +public class Counter { + + protected long count = 0; + + public void add(long value){ + this.count = this.count + value; + } +} +``` +Imagine if two threads, A and B, are executing the add method on the same instance of the Counter class. There is no way to know when the operating system switches between the two threads. The code is not executed as a single instruction by the Java virtual machine. Rather it is executed along the lines of: + +``` +get this.count from memory into register +add value to register +write register to memory +``` + +Observe what happens with the following mixed execution of threads A and B: + +``` +this.count = 0; +A: reads this.count into a register (0) +B: reads this.count into a register (0) +B: adds value 2 to register +B: writes register value (2) back to memory. this.count now equals 2 +A: adds value 3 to register +A: writes register value (3) back to memory. this.count now equals 3 + ``` + +The two threads added the values 2 and 3 to the counter. Thus the value should have been 5 after the two threads complete execution. However, since the execution of the two threads is interleaved, both threads read the value 0 from memory. Then they add their individual values, 2 and 3, to the value, and write the result back to memory. Instead of 5, the value left in this.count will be the value written by the last thread to write its value. In the above case it is thread A, but it could as well have been thread B. Without proper thread synchronization mechanisms there is no way to know exactly how the thread execution is interleaved. + +## Race Conditions & Critical Sections + +The situation where two threads compete for the same resource, where the sequence in which the resource is accessed is significant, is called race conditions. A code section that leads to race conditions is called a critical section. In the previous example the method add() is a critical section, leading to race conditions. Race conditions can be avoided by proper thread synchronization in critical sections. + From c4b6f014f7686ab6bac956bf6d818ca72e8eaf3e Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 16:33:11 +0800 Subject: [PATCH 094/524] =?UTF-8?q?Delete=20=E8=B5=84=E6=BA=90=E7=AB=9E?= =?UTF-8?q?=E4=BA=89=E5=92=8C=E4=B8=B4=E7=95=8C=E5=8C=BA.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...14\344\270\264\347\225\214\345\214\272.md" | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 "\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" diff --git "a/\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" "b/\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" deleted file mode 100644 index 0ad642b..0000000 --- "a/\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" +++ /dev/null @@ -1,43 +0,0 @@ - -#资源竞争和临界区(Race Conditions and Critical Sections) - -Running more than one thread inside the same application does not by itself cause problems. The problems arise when multiple threads access the same resources. For instance the same memory (variables, arrays, or objects), systems (databases, web services etc.) or files. In fact, problems only arise if one or more of the threads write to these resources. It is safe to let multiple threads read the same resources, as long as the resources do not change. - -Here is a code example that may fail if executed by multiple threads simultaneously: - -``` -public class Counter { - - protected long count = 0; - - public void add(long value){ - this.count = this.count + value; - } -} -``` -Imagine if two threads, A and B, are executing the add method on the same instance of the Counter class. There is no way to know when the operating system switches between the two threads. The code is not executed as a single instruction by the Java virtual machine. Rather it is executed along the lines of: - -``` -get this.count from memory into register -add value to register -write register to memory -``` - -Observe what happens with the following mixed execution of threads A and B: - -``` -this.count = 0; -A: reads this.count into a register (0) -B: reads this.count into a register (0) -B: adds value 2 to register -B: writes register value (2) back to memory. this.count now equals 2 -A: adds value 3 to register -A: writes register value (3) back to memory. this.count now equals 3 - ``` - -The two threads added the values 2 and 3 to the counter. Thus the value should have been 5 after the two threads complete execution. However, since the execution of the two threads is interleaved, both threads read the value 0 from memory. Then they add their individual values, 2 and 3, to the value, and write the result back to memory. Instead of 5, the value left in this.count will be the value written by the last thread to write its value. In the above case it is thread A, but it could as well have been thread B. Without proper thread synchronization mechanisms there is no way to know exactly how the thread execution is interleaved. - -## Race Conditions & Critical Sections - -The situation where two threads compete for the same resource, where the sequence in which the resource is accessed is significant, is called race conditions. A code section that leads to race conditions is called a critical section. In the previous example the method add() is a critical section, leading to race conditions. Race conditions can be avoided by proper thread synchronization in critical sections. - From 2dd05014157020953ed3dd8412afff5ecfb6d55f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 16:55:40 +0800 Subject: [PATCH 095/524] Published with https://stackedit.io/ --- ...11\345\222\214\344\270\264\347\225\214\345\214\272.md" | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" index 0ad642b..42bc1e7 100644 --- "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" +++ "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" @@ -1,11 +1,11 @@ #资源竞争和临界区(Race Conditions and Critical Sections) -Running more than one thread inside the same application does not by itself cause problems. The problems arise when multiple threads access the same resources. For instance the same memory (variables, arrays, or objects), systems (databases, web services etc.) or files. In fact, problems only arise if one or more of the threads write to these resources. It is safe to let multiple threads read the same resources, as long as the resources do not change. +在一个应用程序中运行多个线程这本身不会导致什么问题。问题在于多个线程同时对同一资源进行存取,例如同样的内存空间(变量、数组或对象),系统资源(数据库,文件系统等等)。如果是多个线程对同一资源进行读取,则不会有任何问题。 -Here is a code example that may fail if executed by multiple threads simultaneously: +以下的代码,如果有多个线程同时执行,则会导致问题: -``` +```Java public class Counter { protected long count = 0; @@ -15,6 +15,8 @@ public class Counter { } } ``` + + Imagine if two threads, A and B, are executing the add method on the same instance of the Counter class. There is no way to know when the operating system switches between the two threads. The code is not executed as a single instruction by the Java virtual machine. Rather it is executed along the lines of: ``` From 68b2292a2de6b7765342879151eeb10569e75b19 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 17:04:09 +0800 Subject: [PATCH 096/524] Published with https://stackedit.io/ --- ...1\345\222\214\344\270\264\347\225\214\345\214\272.md" | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" index 42bc1e7..937476c 100644 --- "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" +++ "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" @@ -16,13 +16,12 @@ public class Counter { } ``` - -Imagine if two threads, A and B, are executing the add method on the same instance of the Counter class. There is no way to know when the operating system switches between the two threads. The code is not executed as a single instruction by the Java virtual machine. Rather it is executed along the lines of: +想象一下,有两个线程:`A`和`B`,同时执行Counter类的实例的一个`add()`方法。操作系统中的线程调度如何进行,我们是无法进行预测的。并且,这个方法的代码在JVM内部并不是作为一个单独的指令执行的,而是有如下步骤: ``` -get this.count from memory into register -add value to register -write register to memory +从内存中获取this.count的值到寄存器 +把value的值加到寄存器 +把寄存器中的值写到内存 ``` Observe what happens with the following mixed execution of threads A and B: From 2593ef8e9ea31ff15aa0894b68e7adfb318b13fe Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 17:16:22 +0800 Subject: [PATCH 097/524] Published with https://stackedit.io/ --- ...222\214\344\270\264\347\225\214\345\214\272.md" | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" index 937476c..a226211 100644 --- "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" +++ "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" @@ -19,12 +19,12 @@ public class Counter { 想象一下,有两个线程:`A`和`B`,同时执行Counter类的实例的一个`add()`方法。操作系统中的线程调度如何进行,我们是无法进行预测的。并且,这个方法的代码在JVM内部并不是作为一个单独的指令执行的,而是有如下步骤: ``` -从内存中获取this.count的值到寄存器 -把value的值加到寄存器 -把寄存器中的值写到内存 +get this.count from memory into register +add value to register +write register to memory ``` -Observe what happens with the following mixed execution of threads A and B: +观察下面A线程和B线程的运行过程和结果: ``` this.count = 0; @@ -36,9 +36,11 @@ A: adds value 3 to register A: writes register value (3) back to memory. this.count now equals 3 ``` -The two threads added the values 2 and 3 to the counter. Thus the value should have been 5 after the two threads complete execution. However, since the execution of the two threads is interleaved, both threads read the value 0 from memory. Then they add their individual values, 2 and 3, to the value, and write the result back to memory. Instead of 5, the value left in this.count will be the value written by the last thread to write its value. In the above case it is thread A, but it could as well have been thread B. Without proper thread synchronization mechanisms there is no way to know exactly how the thread execution is interleaved. + 线程A和线程B分别加2和3到counter中,在正常情况下,counter的结果应该为5。然而,由于两个线程的执行是互相交织的,两个线程同时从内存中读取0值到寄存器。然后它们分别把2和3跟0相加,最后由线程A把寄存器中的值写回到内存中,所以执行的最后结果是3。在上面的例子中,最后由线程A把3写到内存中,而实际上也可能是线程B。如果没有适当的同步机制,那么我们无从知晓这两个线程间到底如何交织执行。 + + -## Race Conditions & Critical Sections +## 资源竞争和临界点(Race Conditions & Critical Sections) The situation where two threads compete for the same resource, where the sequence in which the resource is accessed is significant, is called race conditions. A code section that leads to race conditions is called a critical section. In the previous example the method add() is a critical section, leading to race conditions. Race conditions can be avoided by proper thread synchronization in critical sections. From ee530215deee5f88b47ff38d7586a4aab3d75d50 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 17:28:51 +0800 Subject: [PATCH 098/524] Published with https://stackedit.io/ --- ...272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" index a226211..2e1818f 100644 --- "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" +++ "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" @@ -42,5 +42,6 @@ A: writes register value (3) back to memory. this.count now equals 3 ## 资源竞争和临界点(Race Conditions & Critical Sections) -The situation where two threads compete for the same resource, where the sequence in which the resource is accessed is significant, is called race conditions. A code section that leads to race conditions is called a critical section. In the previous example the method add() is a critical section, leading to race conditions. Race conditions can be avoided by proper thread synchronization in critical sections. +当多个线程对同一个资源进行竞争,访问这个资源的顺序是非常重要的,称之为**资源竞争**(he situation where two threads compete for the same resource, where the sequence in which the resource is accessed is significant, is called race conditions)。可以引起资源竞争的代码区域,称之为**临界区**。在前面的示例中,`add()`方法就是一个临界区。资源竞争可以通过在临界区进行适当的**线程同步**来避免。 + From 5faef7ffc245af231226d6f1fdc146f7848758ae Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 10 Sep 2014 17:35:59 +0800 Subject: [PATCH 099/524] Published with https://stackedit.io/ --- ...4\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" | 1 - 1 file changed, 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" index 2e1818f..9294181 100644 --- "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" +++ "b/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" @@ -7,7 +7,6 @@ ```Java public class Counter { - protected long count = 0; public void add(long value){ From 422b1c2fd2dbf9b3cbba70d8d2624d38dbf331ea Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 15:50:03 +0800 Subject: [PATCH 100/524] Published with https://stackedit.io/ --- Java-NIO/05.Java NIO Scatter, Gather.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Java-NIO/05.Java NIO Scatter, Gather.md b/Java-NIO/05.Java NIO Scatter, Gather.md index 66f3482..55c571f 100644 --- a/Java-NIO/05.Java NIO Scatter, Gather.md +++ b/Java-NIO/05.Java NIO Scatter, Gather.md @@ -7,13 +7,13 @@ A scattering read from a channel is a read operation that reads data into more t A gathering write to a channel is a write operation that writes data from more than one buffer into a single channel. Thus, the channel "gathers" the data from multiple buffers into one channel. Scatter / gather can be really useful in situations where you need to work with various parts of the transmitted data separately. For instance, if a message consists of a header and a body, you might keep the header and body in separate buffers. Doing so may make it easier for you to work with header and body separately. - Scattering Reads A "scattering read" reads data from a single channel into multiple buffers. Here is an illustration of that principle: Here is an illustration of the Scatter principle: + Java NIO: Scattering Read Java NIO: Scattering Read Here is a code example that shows how to perform a scattering read: @@ -32,6 +32,7 @@ Gathering Writes A "gathering write" writes data from multiple buffers into a single channel. Here is an illustration of that principle: + Java NIO: Gathering Write Java NIO: Gathering Write Here is a code example that shows how to perform a gathering write: From 95be54460ddb74d1856d207294199fb1de627aed Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 16:23:14 +0800 Subject: [PATCH 101/524] Published with https://stackedit.io/ --- Java-NIO/05.Java NIO Scatter, Gather.md | 39 +++++++++++++------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/Java-NIO/05.Java NIO Scatter, Gather.md b/Java-NIO/05.Java NIO Scatter, Gather.md index 55c571f..0d14d07 100644 --- a/Java-NIO/05.Java NIO Scatter, Gather.md +++ b/Java-NIO/05.Java NIO Scatter, Gather.md @@ -1,42 +1,43 @@ #05.Java NIO Scatter, Gather -Java NIO comes with built-in scatter / gather support. Scatter / gather are concepts used in reading from, and writing to channels. +Java NIO开始支持scatter/gater。scatter和gather分别用于从Channel中读取数据和写入数据到Channel中。 -A scattering read from a channel is a read operation that reads data into more than one buffer. Thus, the channel "scatters" the data from the channel into multiple buffers. +**分散(Scatter)**操作是指**将同一个通道(Channel)的数据读到多个缓冲区(Buffer)中**。 -A gathering write to a channel is a write operation that writes data from more than one buffer into a single channel. Thus, the channel "gathers" the data from multiple buffers into one channel. +**聚集(Gather)**是指**将多个缓冲区(Buffer)的数据写入到同一个通道(Channel)中**。 -Scatter / gather can be really useful in situations where you need to work with various parts of the transmitted data separately. For instance, if a message consists of a header and a body, you might keep the header and body in separate buffers. Doing so may make it easier for you to work with header and body separately. -Scattering Reads +分散/聚集(scatter/gather)操作非常适用于一些需要把数据分开几个不同的部分进行处理的场景。例如处理固定大小的header和body的数据,你可以将header和body中的数据分别用不同的缓冲区中进行处理。 -A "scattering read" reads data from a single channel into multiple buffers. Here is an illustration of that principle: +##分散读取(Scattering Reads) -Here is an illustration of the Scatter principle: +分散读取是指**将同一个通道中的数据读到不同的缓冲区中**。如下图所示:  -Java NIO: Scattering Read -Java NIO: Scattering Read -Here is a code example that shows how to perform a scattering read: +下面的代码演示了如何使用Scatterring Reads: + +```Java ByteBuffer header = ByteBuffer.allocate(128); ByteBuffer body = ByteBuffer.allocate(1024); ByteBuffer[] bufferArray = { header, body }; -channel.read(buffers); -Notice how the buffers are first inserted into an array, then the array passed as parameter to the channel.read() method. The read() method then writes data from the channel in the sequence the buffers occur in the array. Once a buffer is full, the channel moves on to fill the next buffer. +channel.read(bufferArray ); +``` + +注意首先要将buffers插入到数组中,然后在再数组作为`channel.read()`的参数。`channel.read()`方法会依次将数组的缓冲区填满,上面的例子中,先填满header缓存区,然后再填满body缓冲区。 -The fact that scattering reads fill up one buffer before moving on to the next, means that it is not suited for dynamically sized message parts. In other words, if you have a header and a body, and the header is fixed size (e.g. 128 bytes), then a scattering read works fine. +由于分散读取(Scattering Reads)在移动到下个缓冲区前,必须填满当前的缓冲区,所以分散操作并不适用于大小不固定的数据体。换言之,上面的例子中,header必须填充128个字节,否则无法正常工作。 -Gathering Writes +##(聚集写入)Gathering Writes -A "gathering write" writes data from multiple buffers into a single channel. Here is an illustration of that principle: +**聚集(Gather)**是指**将多个缓冲区(Buffer)的数据写入到同一个通道(Channel)中**。。如下图所示:  -Java NIO: Gathering Write -Java NIO: Gathering Write -Here is a code example that shows how to perform a gathering write: +下面的代码演示了如何使用Gathering Writes: + +```Java ByteBuffer header = ByteBuffer.allocate(128); ByteBuffer body = ByteBuffer.allocate(1024); @@ -45,4 +46,6 @@ ByteBuffer body = ByteBuffer.allocate(1024); ByteBuffer[] bufferArray = { header, body }; channel.write(buffers); +``` + The array of buffers are passed into the write() method, which writes the content of the buffers in the sequence they are encountered in the array. Only the data between position and limit of the buffers is written. Thus, if a buffer has a capacity of 128 bytes, but only contains 58 bytes, only 58 bytes are written from that buffer to the channel. Thus, a gathering write works fine with dynamically sized message parts, in contrast to scattering reads. \ No newline at end of file From 966cf31f42683256b3a34532a2fafe35e84e70f4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 16:34:00 +0800 Subject: [PATCH 102/524] Published with https://stackedit.io/ --- Java-NIO/05.Java NIO Scatter, Gather.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Java-NIO/05.Java NIO Scatter, Gather.md b/Java-NIO/05.Java NIO Scatter, Gather.md index 0d14d07..f984a50 100644 --- a/Java-NIO/05.Java NIO Scatter, Gather.md +++ b/Java-NIO/05.Java NIO Scatter, Gather.md @@ -48,4 +48,4 @@ ByteBuffer[] bufferArray = { header, body }; channel.write(buffers); ``` -The array of buffers are passed into the write() method, which writes the content of the buffers in the sequence they are encountered in the array. Only the data between position and limit of the buffers is written. Thus, if a buffer has a capacity of 128 bytes, but only contains 58 bytes, only 58 bytes are written from that buffer to the channel. Thus, a gathering write works fine with dynamically sized message parts, in contrast to scattering reads. \ No newline at end of file +缓冲区数组作为参数传递给`channel.write()`方法,这个方法依次从缓冲区中写入数据到通道中。缓冲区中有效数据才会写入到通道中,例如header缓冲区的容量为128字节,但实际有效数据位58字节,所以实际上header缓冲区中只有前58字节写入到了通道。因此,与分散读取操作不同,聚集写入(Gathering Writes)操作适用于大小不固定的数据块。 From 55eca2574a264b929c167e91e87d9e847e3c8f70 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 16:35:40 +0800 Subject: [PATCH 103/524] Published with https://stackedit.io/ --- ...IO\351\200\211\346\213\251\345\231\250.md" | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 "Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" new file mode 100644 index 0000000..e76b551 --- /dev/null +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -0,0 +1,205 @@ +#06.Java NIO选择器 + +A Selector is a Java NIO component which can examine one or more NIO Channel's, and determine which channels are ready for e.g. reading or writing. This way a single thread can manage multiple channels, and thus multiple network connections. + +Why Use a Selector? + +The advantage of using just a single thread to handle multiple channels is that you need less threads to handle the channels. Actually, you can use just one thread to handle all of your channels. Switching between threads is expensive for an operating system, and each thread takes up some resources (memory) in the operating system too. Therefore, the less threads you use, the better. + +Keep in mind though, that modern operating systems and CPU's become better and better at multitasking, so the overheads of multithreading becomes smaller over time. In fact, if a CPU has multiple cores, you might be wasting CPU power by not multitasking. Anyways, that design discussion belongs in a different text. It suffices to say here, that you can handle multiple channels with a single thread, using a Selector. + +Here is an illustration of a thread using a Selector to handle 3 Channel's: + +Java NIO: Selectors +Java NIO: A Thread uses a Selector to handle 3 Channel's +Creating a Selector + +You create a Selector by calling the Selector.open() method, like this: + +Selector selector = Selector.open(); +Registering Channels with the Selector + +In order to use a Channel with a Selector you must register the Channel with the Selector. This is done using the SelectableChannel.register() method, like this: + +channel.configureBlocking(false); + +SelectionKey key = channel.register(selector, SelectionKey.OP_READ); +The Channel must be in non-blocking mode to be used with a Selector. This means that you cannot use FileChannel's with a Selector since FileChannel's cannot be switched into non-blocking mode. Socket channels will work fine though. + +Notice the second parameter of the register() method. This is an "interest set", meaning what events you are interested in listening for in the Channel, via the Selector. There are four different events you can listen for: + +Connect +Accept +Read +Write +A channel that "fires an event" is also said to be "ready" for that event. So, a channel that has connected successfully to another server is "connect ready". A server socket channel which accepts an incoming connection is "accept" ready. A channel that has data ready to be read is "read" ready. A channel that is ready for you to write data to it, is "write" ready. + +These four events are represented by the four SelectionKey constants: + +SelectionKey.OP_CONNECT +SelectionKey.OP_ACCEPT +SelectionKey.OP_READ +SelectionKey.OP_WRITE +If you are interested in more than one event, OR the constants together, like this: + +int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; +I'll return to the interest set a bit further down in this text. + +SelectionKey's + +As you saw in the previous section, when you register a Channel with a Selector the register() method returns a SelectionKey objects. This SelectionKey object contains a few interesting properties: + +The interest set +The ready set +The Channel +The Selector +An attached object (optional) +I'll describe these properties below. + +Interest Set + +The interest set is the set of events you are interested in "selecting", as described in the section "Registering Channels with the Selector". You can read and write that interest set via the SelectionKey like this: + +int interestSet = selectionKey.interestOps(); + +boolean isInterestedInAccept = interestSet & SelectionKey.OP_ACCEPT; +boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT; +boolean isInterestedInRead = interestSet & SelectionKey.OP_READ; +boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE; +As you can see, you can AND the interest set with the given SelectionKey constant to find out if a certain event is in the interest set. + +Ready Set + +The ready set is the set of operations the channel is ready for. You will primarily be accessing the ready set after a selection. Selection is explained in a later section. You access the ready set like this: + +int readySet = selectionKey.readyOps(); +You can test in the same way as with the interest set, what events / operations the channel is ready for. But, you can also use these four methods instead, which all reaturn a boolean: + +selectionKey.isAcceptable(); +selectionKey.isConnectable(); +selectionKey.isReadable(); +selectionKey.isWritable(); +Channel + Selector + +Accessing the channel + selector from the SelectionKey is trivial. Here is how it's done: + +Channel channel = selectionKey.channel(); + +Selector selector = selectionKey.selector(); +Attaching Objects + +You can attach an object to a SelectionKey this is a handy way of recognizing a given channel, or attaching further information to the channel. For instance, you may attach the Buffer you are using with the channel, or an object containing more aggregate data. Here is how you attach objects: + +selectionKey.attach(theObject); + +Object attachedObj = selectionKey.attachment(); +You can also attach an object already while registering the Channel with the Selector, in the register() method. Here is how that looks: + +SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); +Selecting Channels via a Selector + +Once you have register one or more channels with a Selector you can call one of the select() methods. These methods return the channels that are "ready" for the events you are interested in (connect, accept, read or write). In other words, if you are interested in channels that are ready for reading, you will receive the channels that are ready for reading from the select() methods. + +Here are the select() methods: + +int select() +int select(long timeout) +int selectNow() +select() blocks until at least one channel is ready for the events you registered for. + +select(long timeout) does the same as select() except it blocks for a maximum of timeout milliseconds (the parameter). + +selectNow() doesn't block at all. It returns immediately with whatever channels are ready. + +The int returned by the select() methods tells how many channels are ready. That is, how many channels that became ready since last time you called select(). If you call select() and it returns 1 because one channel has become ready, and you call select() one more time, and one more channel has become ready, it will return 1 again. If you have done nothing with the first channel that was ready, you now have 2 ready channels, but only one channel had become ready between each select() call. + +selectedKeys() + +Once you have called one of the select() methods and its return value has indicated that one or more channels are ready, you can access the ready channels via the "selected key set", by calling the selectors selectedKeys() method. Here is how that looks: + +Set selectedKeys = selector.selectedKeys(); +When you register a channel with a Selector the Channel.register() method returns a SelectionKey object. This key represents that channels registration with that selector. It is these keys you can access via the selectedKeySet() method. From the SelectionKey. + +You can iterate this selected key set to access the ready channels. Here is how that looks: + +Set selectedKeys = selector.selectedKeys(); + +Iterator keyIterator = selectedKeys.iterator(); + +while(keyIterator.hasNext()) { + + SelectionKey key = keyIterator.next(); + + if(key.isAcceptable()) { + // a connection was accepted by a ServerSocketChannel. + + } else if (key.isConnectable()) { + // a connection was established with a remote server. + + } else if (key.isReadable()) { + // a channel is ready for reading + + } else if (key.isWritable()) { + // a channel is ready for writing + } + + keyIterator.remove(); +} +This loop iterates the keys in the selected key set. For each key it tests the key to determine what the channel referenced by the key is ready for. + +Notice the keyIterator.remove() call at the end of each iteration. The Selector does not remove the SelectionKey instances from the selected key set itself. You have to do this, when you are done processing the channel. The next time the channel becomes "ready" the Selector will add it to the selected key set again. + +The channel returned by the SelectionKey.channel() method should be cast to the channel you need to work with, e.g a ServerSocketChannel or SocketChannel etc. + +wakeUp() + +A thread that has called the select() method which is blocked, can be made to leave the select() method, even if no channels are yet ready. This is done by having a different thread call the Selector.wakeup() method on the Selector which the first thread has called select() on. The thread waiting inside select() will then return immediately. + +If a different thread calls wakeup() and no thread is currently blocked inside select(), the next thread that calls select() will "wake up" immediately. + +close() + +When you are finished with the Selector you call its close() method. This closes the Selector and invalidates all SelectionKey instances registered with this Selector. The channels themselves are not closed. + +Full Selector Example + +Here is a full example which opens a Selector, registers a channel with it (the channel instantiation is left out), and keeps monitoring the Selector for "readiness" of the four events (accept, connect, read, write). + +Selector selector = Selector.open(); + +channel.configureBlocking(false); + +SelectionKey key = channel.register(selector, SelectionKey.OP_READ); + + +while(true) { + + int readyChannels = selector.select(); + + if(readyChannels == 0) continue; + + + Set selectedKeys = selector.selectedKeys(); + + Iterator keyIterator = selectedKeys.iterator(); + + while(keyIterator.hasNext()) { + + SelectionKey key = keyIterator.next(); + + if(key.isAcceptable()) { + // a connection was accepted by a ServerSocketChannel. + + } else if (key.isConnectable()) { + // a connection was established with a remote server. + + } else if (key.isReadable()) { + // a channel is ready for reading + + } else if (key.isWritable()) { + // a channel is ready for writing + } + + keyIterator.remove(); + } +} \ No newline at end of file From f0519c572b1b9078fb99e64629fa05badcfa9b15 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 16:36:58 +0800 Subject: [PATCH 104/524] Published with https://stackedit.io/ --- "Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" | 3 +++ 1 file changed, 3 insertions(+) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index e76b551..9a8f321 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -11,6 +11,9 @@ Keep in mind though, that modern operating systems and CPU's become better and b Here is an illustration of a thread using a Selector to handle 3 Channel's: Java NIO: Selectors + + + Java NIO: A Thread uses a Selector to handle 3 Channel's Creating a Selector From 9fe1219ca35a072d673ef39577ad2150d6708ade Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 16:38:45 +0800 Subject: [PATCH 105/524] Published with https://stackedit.io/ --- ...NIO\351\200\211\346\213\251\345\231\250.md" | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index 9a8f321..537b862 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -2,7 +2,7 @@ A Selector is a Java NIO component which can examine one or more NIO Channel's, and determine which channels are ready for e.g. reading or writing. This way a single thread can manage multiple channels, and thus multiple network connections. -Why Use a Selector? +##Why Use a Selector? The advantage of using just a single thread to handle multiple channels is that you need less threads to handle the channels. Actually, you can use just one thread to handle all of your channels. Switching between threads is expensive for an operating system, and each thread takes up some resources (memory) in the operating system too. Therefore, the less threads you use, the better. @@ -10,10 +10,12 @@ Keep in mind though, that modern operating systems and CPU's become better and b Here is an illustration of a thread using a Selector to handle 3 Channel's: -Java NIO: Selectors +##Java NIO: Selectors  + + Java NIO: A Thread uses a Selector to handle 3 Channel's Creating a Selector @@ -48,7 +50,7 @@ If you are interested in more than one event, OR the constants together, like th int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; I'll return to the interest set a bit further down in this text. -SelectionKey's +##SelectionKey's As you saw in the previous section, when you register a Channel with a Selector the register() method returns a SelectionKey objects. This SelectionKey object contains a few interesting properties: @@ -59,7 +61,7 @@ The Selector An attached object (optional) I'll describe these properties below. -Interest Set +###Interest Set The interest set is the set of events you are interested in "selecting", as described in the section "Registering Channels with the Selector". You can read and write that interest set via the SelectionKey like this: @@ -71,7 +73,7 @@ boolean isInterestedInRead = interestSet & SelectionKey.OP_READ; boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE; As you can see, you can AND the interest set with the given SelectionKey constant to find out if a certain event is in the interest set. -Ready Set +###Ready Set The ready set is the set of operations the channel is ready for. You will primarily be accessing the ready set after a selection. Selection is explained in a later section. You access the ready set like this: @@ -154,17 +156,17 @@ Notice the keyIterator.remove() call at the end of each iteration. The Selector The channel returned by the SelectionKey.channel() method should be cast to the channel you need to work with, e.g a ServerSocketChannel or SocketChannel etc. -wakeUp() +###wakeUp() A thread that has called the select() method which is blocked, can be made to leave the select() method, even if no channels are yet ready. This is done by having a different thread call the Selector.wakeup() method on the Selector which the first thread has called select() on. The thread waiting inside select() will then return immediately. If a different thread calls wakeup() and no thread is currently blocked inside select(), the next thread that calls select() will "wake up" immediately. -close() +###close() When you are finished with the Selector you call its close() method. This closes the Selector and invalidates all SelectionKey instances registered with this Selector. The channels themselves are not closed. -Full Selector Example +##Full Selector Example Here is a full example which opens a Selector, registers a channel with it (the channel instantiation is left out), and keeps monitoring the Selector for "readiness" of the four events (accept, connect, read, write). From 9d2946a885342cf044ef199d0573db0afb6adb9c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 17:01:38 +0800 Subject: [PATCH 106/524] Published with https://stackedit.io/ --- ...IO\351\200\211\346\213\251\345\231\250.md" | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index 537b862..bf4e7db 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -1,28 +1,29 @@ #06.Java NIO选择器 -A Selector is a Java NIO component which can examine one or more NIO Channel's, and determine which channels are ready for e.g. reading or writing. This way a single thread can manage multiple channels, and thus multiple network connections. +选择器(Selector)是Java NIO中的一个组件,它用于检测一个或多个通道,并确定哪些通道可以进行读、写。这就是为什么Java NIO中可以使用单个线程对多个通道或网络连接进行管理。 -##Why Use a Selector? -The advantage of using just a single thread to handle multiple channels is that you need less threads to handle the channels. Actually, you can use just one thread to handle all of your channels. Switching between threads is expensive for an operating system, and each thread takes up some resources (memory) in the operating system too. Therefore, the less threads you use, the better. +##为何要使用选择器(Why Use a Selector?) -Keep in mind though, that modern operating systems and CPU's become better and better at multitasking, so the overheads of multithreading becomes smaller over time. In fact, if a CPU has multiple cores, you might be wasting CPU power by not multitasking. Anyways, that design discussion belongs in a different text. It suffices to say here, that you can handle multiple channels with a single thread, using a Selector. +使用选择器的优势在于:**使用单个线程就可以对多个管道进行操作,从而可以减少处理通道的线程数量**。实际上,你可以仅仅使用一个线程来处理所有的通道。在操作系统中,线程的切换是非常昂贵的,并且,每个线程需要消耗一定的系统资源(例如内存)。因此,线程使用越少越好。 -Here is an illustration of a thread using a Selector to handle 3 Channel's: +不过,随着操作系统软硬件的更新迭代,多线程的开销越来越小,性能也越来越优异。而事实上,如果计算机拥有多个CPU内核,这时候如果不采用多线程,反而是对CPU资源的浪费。然而,这已不属于本教程讨论的范畴。 -##Java NIO: Selectors +下面的图片描绘了如何使用一个选择器来处理3个通道:  - +##创建选择器(Creating a Selector) -Java NIO: A Thread uses a Selector to handle 3 Channel's -Creating a Selector - -You create a Selector by calling the Selector.open() method, like this: +可以通过`Selector.open()`方法来创建选择器: +```Java Selector selector = Selector.open(); -Registering Channels with the Selector +``` + +#Registering Channels with the Selector + + In order to use a Channel with a Selector you must register the Channel with the Selector. This is done using the SelectableChannel.register() method, like this: From 01b8d93b42fdb45d9cb0c0b7086faaaeafb32acd Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 17:11:36 +0800 Subject: [PATCH 107/524] Published with https://stackedit.io/ --- ...a NIO\351\200\211\346\213\251\345\231\250.md" | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index bf4e7db..308b6aa 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -23,14 +23,22 @@ Selector selector = Selector.open(); #Registering Channels with the Selector +为了让选择器能够处理通道,必须向选择器注册需要处理的通道,调用`SelectableChannel.register()`方法来完成注册: - -In order to use a Channel with a Selector you must register the Channel with the Selector. This is done using the SelectableChannel.register() method, like this: - +``` channel.configureBlocking(false); SelectionKey key = channel.register(selector, SelectionKey.OP_READ); -The Channel must be in non-blocking mode to be used with a Selector. This means that you cannot use FileChannel's with a Selector since FileChannel's cannot be switched into non-blocking mode. Socket channels will work fine though. +``` + +注册的通道必须先设置为**非阻塞模式(non-blocking mode)**。由于**FileChannel**不能设置为非阻塞模式,所以FileChannel不能进行注册,而**SocketChanne**l则可以。 + +注意`SelectableChannel.register()`方法的第二个参数。这个参数代表着**选择器需要监听通道的事件类型**。总共有四种不同的事件类型: + + - Connect + - Accept + - Read + - Write Notice the second parameter of the register() method. This is an "interest set", meaning what events you are interested in listening for in the Channel, via the Selector. There are four different events you can listen for: From 45c62bda1cbfebf936159ebeb1a54d1d16298846 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 17:30:22 +0800 Subject: [PATCH 108/524] Published with https://stackedit.io/ --- ...IO\351\200\211\346\213\251\345\231\250.md" | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index 308b6aa..fe94782 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -35,29 +35,23 @@ SelectionKey key = channel.register(selector, SelectionKey.OP_READ); 注意`SelectableChannel.register()`方法的第二个参数。这个参数代表着**选择器需要监听通道的事件类型**。总共有四种不同的事件类型: - - Connect - - Accept - - Read - - Write +通道**触发一个事件**,我们称之为**事件就绪**。所以,如果通道跟远程服务器建立了连接,称之为**连接就绪**;服务器socket接受客户端连接,称为**接收就绪**;通道中有数据可读,称为**读就绪**,可向通道中写数据,称为**写就绪**。 -Notice the second parameter of the register() method. This is an "interest set", meaning what events you are interested in listening for in the Channel, via the Selector. There are four different events you can listen for: - -Connect -Accept -Read -Write -A channel that "fires an event" is also said to be "ready" for that event. So, a channel that has connected successfully to another server is "connect ready". A server socket channel which accepts an incoming connection is "accept" ready. A channel that has data ready to be read is "read" ready. A channel that is ready for you to write data to it, is "write" ready. - -These four events are represented by the four SelectionKey constants: +以上四个事件分别由`SelectionKey`类中的四个常量来表示: +```Java SelectionKey.OP_CONNECT SelectionKey.OP_ACCEPT SelectionKey.OP_READ SelectionKey.OP_WRITE -If you are interested in more than one event, OR the constants together, like this: +``` -int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; -I'll return to the interest set a bit further down in this text. +如果需要监听多个事件,可以使用OR操作符: + +```Java +int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; +``` +由于SelectionKey中是四个常量OP\_READ、OP\_WRITE、OP\_CONNECT、OP\_ACCEPTF分别用二进制0001、0010、0100、1000表示,所以可以通过interestSet中的二进制判断监听的事件类型。 ##SelectionKey's From 342052f4ebf52897f6139dbeba69ba7d5c30ff77 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 17:35:57 +0800 Subject: [PATCH 109/524] Published with https://stackedit.io/ --- ...va NIO\351\200\211\346\213\251\345\231\250.md" | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index fe94782..8ec980e 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -55,17 +55,20 @@ int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; ##SelectionKey's -As you saw in the previous section, when you register a Channel with a Selector the register() method returns a SelectionKey objects. This SelectionKey object contains a few interesting properties: +上面的例子中,当调用`SelectableChannel.register()`向选择器注册通道后,该返回会返回一个`SeletionKey`对象。该`SelectionKey`对象包含以下属性: -The interest set -The ready set -The Channel -The Selector +``` +The interest set(监听的事件集合) +The ready set(就绪的事件集合) +The Channel(通道) +The Selector(选择器) An attached object (optional) -I'll describe these properties below. +``` ###Interest Set + + The interest set is the set of events you are interested in "selecting", as described in the section "Registering Channels with the Selector". You can read and write that interest set via the SelectionKey like this: int interestSet = selectionKey.interestOps(); From 1d0e50221f144b6c12b10a4a443c5cc020d12aae Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 17:44:50 +0800 Subject: [PATCH 110/524] Published with https://stackedit.io/ --- ...IO\351\200\211\346\213\251\345\231\250.md" | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index 8ec980e..4d0af7c 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -65,57 +65,71 @@ The Selector(选择器) An attached object (optional) ``` -###Interest Set +###Interest Set(监听的事件集合) +InterestSet表示的是监听的时间集合,可以通过`SelctionKey.interestOPs()`方法获取监听的时间集合,它是一个int类型数据,由于SelectionKey中是四个常量OP\_READ、OP\_WRITE、OP\_CONNECT、OP\_ACCEPTF分别用二进制0001、0010、0100、1000表示,所以,我们可以通过**按位与**操作判断监听的事件类型: - -The interest set is the set of events you are interested in "selecting", as described in the section "Registering Channels with the Selector". You can read and write that interest set via the SelectionKey like this: - +```Java int interestSet = selectionKey.interestOps(); boolean isInterestedInAccept = interestSet & SelectionKey.OP_ACCEPT; boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT; boolean isInterestedInRead = interestSet & SelectionKey.OP_READ; -boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE; -As you can see, you can AND the interest set with the given SelectionKey constant to find out if a certain event is in the interest set. +boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE; +``` -###Ready Set +###Ready Set(就绪集合) -The ready set is the set of operations the channel is ready for. You will primarily be accessing the ready set after a selection. Selection is explained in a later section. You access the ready set like this: +可以通过`SelectionKey.readyOps()`方法获取就绪集合。同样地,通过按位与操作判断就绪的事件类型: +```Java int readySet = selectionKey.readyOps(); -You can test in the same way as with the interest set, what events / operations the channel is ready for. But, you can also use these four methods instead, which all reaturn a boolean: selectionKey.isAcceptable(); selectionKey.isConnectable(); selectionKey.isReadable(); selectionKey.isWritable(); -Channel + Selector +``` + + +###Channel + Selector(通道和选择器) Accessing the channel + selector from the SelectionKey is trivial. Here is how it's done: +```Java Channel channel = selectionKey.channel(); Selector selector = selectionKey.selector(); -Attaching Objects +``` + +###Attaching Objects You can attach an object to a SelectionKey this is a handy way of recognizing a given channel, or attaching further information to the channel. For instance, you may attach the Buffer you are using with the channel, or an object containing more aggregate data. Here is how you attach objects: +```Java selectionKey.attach(theObject); Object attachedObj = selectionKey.attachment(); +``` + You can also attach an object already while registering the Channel with the Selector, in the register() method. Here is how that looks: +```Java SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); -Selecting Channels via a Selector +``` + +##Selecting Channels via a Selector Once you have register one or more channels with a Selector you can call one of the select() methods. These methods return the channels that are "ready" for the events you are interested in (connect, accept, read or write). In other words, if you are interested in channels that are ready for reading, you will receive the channels that are ready for reading from the select() methods. Here are the select() methods: +```Java int select() int select(long timeout) int selectNow() +``` + select() blocks until at least one channel is ready for the events you registered for. select(long timeout) does the same as select() except it blocks for a maximum of timeout milliseconds (the parameter). @@ -128,11 +142,15 @@ selectedKeys() Once you have called one of the select() methods and its return value has indicated that one or more channels are ready, you can access the ready channels via the "selected key set", by calling the selectors selectedKeys() method. Here is how that looks: +```Java Set selectedKeys = selector.selectedKeys(); +``` + When you register a channel with a Selector the Channel.register() method returns a SelectionKey object. This key represents that channels registration with that selector. It is these keys you can access via the selectedKeySet() method. From the SelectionKey. You can iterate this selected key set to access the ready channels. Here is how that looks: +```Java Set selectedKeys = selector.selectedKeys(); Iterator keyIterator = selectedKeys.iterator(); @@ -156,6 +174,8 @@ while(keyIterator.hasNext()) { keyIterator.remove(); } +``` + This loop iterates the keys in the selected key set. For each key it tests the key to determine what the channel referenced by the key is ready for. Notice the keyIterator.remove() call at the end of each iteration. The Selector does not remove the SelectionKey instances from the selected key set itself. You have to do this, when you are done processing the channel. The next time the channel becomes "ready" the Selector will add it to the selected key set again. @@ -182,7 +202,7 @@ channel.configureBlocking(false); SelectionKey key = channel.register(selector, SelectionKey.OP_READ); - +```Java while(true) { int readyChannels = selector.select(); @@ -213,4 +233,5 @@ while(true) { keyIterator.remove(); } -} \ No newline at end of file +} +``` \ No newline at end of file From 8facf9658346d4acbdbdcd4cab8bc599abfbc599 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 17:56:31 +0800 Subject: [PATCH 111/524] Published with https://stackedit.io/ --- ...ava NIO\351\200\211\346\213\251\345\231\250.md" | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index 4d0af7c..d3ee446 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -120,15 +120,13 @@ SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); ##Selecting Channels via a Selector -Once you have register one or more channels with a Selector you can call one of the select() methods. These methods return the channels that are "ready" for the events you are interested in (connect, accept, read or write). In other words, if you are interested in channels that are ready for reading, you will receive the channels that are ready for reading from the select() methods. + 当向选择器注册一个或多个通道后,可以调用`Selector.slect(...)`方法,这个返回会当前已经就绪的通道(说明该通道有选择器监听的事件就绪)。换言之,如果选择器监听了一个通道的读事件,当该通道有数据可读时,`Selector.select(...)`操作就会返回该通道。 + +有多个重载的`select()`方法: -Here are the select() methods: - -```Java -int select() -int select(long timeout) -int selectNow() -``` +> int select() +> int select(long timeout) +> int selectNow() select() blocks until at least one channel is ready for the events you registered for. From c7b87e1c9615525ae2ebf5883f8d48d44ad8f0c6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 18:00:01 +0800 Subject: [PATCH 112/524] Published with https://stackedit.io/ --- .../06.Java NIO\351\200\211\346\213\251\345\231\250.md" | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index d3ee446..adc4d88 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -128,6 +128,14 @@ SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); > int select(long timeout) > int selectNow() +`select()`方法会阻塞直到有通道事件就绪。 + +`select(long timeout)`方法会阻塞直到有通道事件就绪或超时。 + +`selectNow()`方法不管有没有通道事件就绪,都会立即返回。 + + + select() blocks until at least one channel is ready for the events you registered for. select(long timeout) does the same as select() except it blocks for a maximum of timeout milliseconds (the parameter). From 384f28d4ed30382244030794405d9cc206720faf Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 18:13:38 +0800 Subject: [PATCH 113/524] Published with https://stackedit.io/ --- .../06.Java NIO\351\200\211\346\213\251\345\231\250.md" | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index adc4d88..d75ada0 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -120,7 +120,7 @@ SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); ##Selecting Channels via a Selector - 当向选择器注册一个或多个通道后,可以调用`Selector.slect(...)`方法,这个返回会当前已经就绪的通道(说明该通道有选择器监听的事件就绪)。换言之,如果选择器监听了一个通道的读事件,当该通道有数据可读时,`Selector.select(...)`操作就会返回该通道。 + 当向选择器注册一个或多个通道后,可以调用`Selector.slect(...)`方法,这个返回会当前已经就绪的通道(说明该通道有选择器监听的事件就绪)的个数。换言之,如果选择器监听了一个通道的读事件,当该通道有数据可读时,`Selector.select(...)`操作就会返回 1。 有多个重载的`select()`方法: @@ -142,9 +142,11 @@ select(long timeout) does the same as select() except it blocks for a maximum of selectNow() doesn't block at all. It returns immediately with whatever channels are ready. + + The int returned by the select() methods tells how many channels are ready. That is, how many channels that became ready since last time you called select(). If you call select() and it returns 1 because one channel has become ready, and you call select() one more time, and one more channel has become ready, it will return 1 again. If you have done nothing with the first channel that was ready, you now have 2 ready channels, but only one channel had become ready between each select() call. -selectedKeys() +###selectedKeys() Once you have called one of the select() methods and its return value has indicated that one or more channels are ready, you can access the ready channels via the "selected key set", by calling the selectors selectedKeys() method. Here is how that looks: From 53e0fe2f8ebc19f86166f671176c8a466954a7a4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 18:16:11 +0800 Subject: [PATCH 114/524] Published with https://stackedit.io/ --- ...06.Java NIO\351\200\211\346\213\251\345\231\250.md" | 10 ---------- 1 file changed, 10 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index d75ada0..f8136cd 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -134,16 +134,6 @@ SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); `selectNow()`方法不管有没有通道事件就绪,都会立即返回。 - - -select() blocks until at least one channel is ready for the events you registered for. - -select(long timeout) does the same as select() except it blocks for a maximum of timeout milliseconds (the parameter). - -selectNow() doesn't block at all. It returns immediately with whatever channels are ready. - - - The int returned by the select() methods tells how many channels are ready. That is, how many channels that became ready since last time you called select(). If you call select() and it returns 1 because one channel has become ready, and you call select() one more time, and one more channel has become ready, it will return 1 again. If you have done nothing with the first channel that was ready, you now have 2 ready channels, but only one channel had become ready between each select() call. ###selectedKeys() From 830176ab93769ea8c15a0e7a58161b25f3557094 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 18:23:27 +0800 Subject: [PATCH 115/524] Published with https://stackedit.io/ --- "Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index f8136cd..f315a3f 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -134,7 +134,7 @@ SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); `selectNow()`方法不管有没有通道事件就绪,都会立即返回。 -The int returned by the select() methods tells how many channels are ready. That is, how many channels that became ready since last time you called select(). If you call select() and it returns 1 because one channel has become ready, and you call select() one more time, and one more channel has become ready, it will return 1 again. If you have done nothing with the first channel that was ready, you now have 2 ready channels, but only one channel had become ready between each select() call. +`select()`返回值为int类型,代表从上次调用`select()`方法到现在的就绪通道数量。当你调用select返回1时,则代表上次调用select方法到这次调用之间有一个通道变成了就绪状态,然后,再次调用select方法,如果返回值为1,则说明又有一个通道变成了就绪状态。如果你没对第一个就绪通道进行处理,则此时共有两个就绪通道,虽然最后一次select的返回值为1。 ###selectedKeys() From 09ce0d13195683d65dcb2e02d79a6e778698f178 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 18:39:15 +0800 Subject: [PATCH 116/524] Published with https://stackedit.io/ --- .../06.Java NIO\351\200\211\346\213\251\345\231\250.md" | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index f315a3f..bf8a103 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -134,16 +134,18 @@ SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); `selectNow()`方法不管有没有通道事件就绪,都会立即返回。 -`select()`返回值为int类型,代表从上次调用`select()`方法到现在的就绪通道数量。当你调用select返回1时,则代表上次调用select方法到这次调用之间有一个通道变成了就绪状态,然后,再次调用select方法,如果返回值为1,则说明又有一个通道变成了就绪状态。如果你没对第一个就绪通道进行处理,则此时共有两个就绪通道,虽然最后一次select的返回值为1。 +`select()`返回值为int类型,代表从上次调用`select()`方法到这次的就绪通道数量。当你调用select返回1时,则代表上次调用select方法到这次调用之间有一个通道变成了就绪状态,然后,再次调用select方法,如果返回值为1,则说明又有一个通道变成了就绪状态。如果你没对第一个就绪通道进行处理,则此时共有两个就绪通道,虽然最后一次select的返回值为1。 ###selectedKeys() -Once you have called one of the select() methods and its return value has indicated that one or more channels are ready, you can access the ready channels via the "selected key set", by calling the selectors selectedKeys() method. Here is how that looks: +当你调用select()方法返回值不为0时,则说明有一个或多个通道已经就绪。你可以通过调用`selector.selectedKeys()`获取就绪的通道: ```Java Set selectedKeys = selector.selectedKeys(); ``` +当你通过`SelectableChannel.register()`注册通道时,返回一个SeletionKey对象。 + When you register a channel with a Selector the Channel.register() method returns a SelectionKey object. This key represents that channels registration with that selector. It is these keys you can access via the selectedKeySet() method. From the SelectionKey. You can iterate this selected key set to access the ready channels. Here is how that looks: From 378442cbd00d586ddf2e7e99aa9af677c1009569 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 21:07:48 +0800 Subject: [PATCH 117/524] Published with https://stackedit.io/ --- ...04\346\272\220\345\205\261\344\272\253.md" | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 "Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" diff --git "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" new file mode 100644 index 0000000..a63c446 --- /dev/null +++ "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" @@ -0,0 +1,93 @@ +#06.线程安全与资源共享(Thread Safety and Shared Resources) + +Code that is safe to call by multiple threads simultanously is called thread safe. If a piece of code is thread safe, then it contains no race conditions. Race condition only occur when multiple threads update shared resources. Therefore it is important to know what resources Java threads share when executing. + +##局部变量(Local Variables) + +Local variables are stored in each thread's own stack. That means that local variables are never shared between threads. That also means that all local primitive variables are thread safe. Here is an example of a thread safe local primitive variable: + +public void someMethod(){ + + long threadSafeInt = 0; + + threadSafeInt++; +} + +## 本地变量引用(Local Object References) + +Local references to objects are a bit different. The reference itself is not shared. The object referenced however, is not stored in each threads's local stack. All objects are stored in the shared heap. If an object created locally never escapes the method it was created in, it is thread safe. In fact you can also pass it on to other methods and objects as long as none of these methods or objects make the passed object available to other threads. Here is an example of a thread safe local object: + +public void someMethod(){ + + LocalObject localObject = new LocalObject(); + + localObject.callMethod(); + method2(localObject); +} + +public void method2(LocalObject localObject){ + localObject.setValue("value"); +} + +The LocalObject instance in this example is not returned from the method, nor is it passed to any other objects that are accessible from outside the someMethod() method. Each thread executing the someMethod() method will create its own LocalObject instance and assign it to the localObject reference. Therefore the use of the LocalObject here is thread safe. In fact, the whole method someMethod() is thread safe. Even if the LocalObject instance is passed as parameter to other methods in the same class, or in other classes, the use of it is thread safe. The only exception is of course, if one of the methods called with the LocalObject as parameter, stores the LocalObject instance in a way that allows access to it from other threads. + +##对象成员(Object Members) + +Object members are stored on the heap along with the object. Therefore, if two threads call a method on the same object instance and this method updates object members, the method is not thread safe. Here is an example of a method that is not thread safe: + + +public class NotThreadSafe{ + StringBuilder builder = new StringBuilder(); + + public add(String text){ + this.builder.append(text); + } +} +If two threads call the add() method simultanously on the same NotThreadSafe instance then it leads to race conditions. For instance: + + +NotThreadSafe sharedInstance = new NotThreadSafe(); + +new Thread(new MyRunnable(sharedInstance)).start(); +new Thread(new MyRunnable(sharedInstance)).start(); + +public class MyRunnable implements Runnable{ + NotThreadSafe instance = null; + + public MyRunnable(NotThreadSafe instance){ + this.instance = instance; + } + + public void run(){ + this.instance.add("some text"); + } +} +Notice how the two MyRunnable instances share the same NotThreadSafe instance. Therefore, when they call the add() method on the NotThreadSafe instance it leads to race condition. + +However, if two threads call the add() method simultanously on different instances then it does not lead to race condition. Here is the example from before, but slightly modified: + +new Thread(new MyRunnable(new NotThreadSafe())).start(); +new Thread(new MyRunnable(new NotThreadSafe())).start(); +Now the two threads have each their own instance of NotThreadSafe so their calls to the add method doesn't interfere with each other. The code does not have race condition anymore. So, even if an object is not thread safe it can still be used in a way that doesn't lead to race condition. + +##The Thread Control Escape Rule + +When trying to determine if your code's access of a certain resource is thread safe you can use the thread control escape rule: + +If a resource is created, used and disposed within +the control of the same thread, +and never escapes the control of this thread, +the use of that resource is thread safe. +Resources can be any shared resource like an object, array, file, database connection, socket etc. In Java you do not always explicitly dispose objects, so "disposed" means losing or null'ing the reference to the object. + +Even if the use of an object is thread safe, if that object points to a shared resource like a file or database, your application as a whole may not be thread safe. For instance, if thread 1 and thread 2 each create their own database connections, connection 1 and connection 2, the use of each connection itself is thread safe. But the use of the database the connections point to may not be thread safe. For example, if both threads execute code like this: + +check if record X exists +if not, insert record X +If two threads execute this simultanously, and the record X they are checking for happens to be the same record, there is a risk that both of the threads end up inserting it. This is how: + +Thread 1 checks if record X exists. Result = no +Thread 2 checks if record X exists. Result = no +Thread 1 inserts record X +Thread 2 inserts record X +This could also happen with threads operating on files or other shared resources. Therefore it is important to distinguish between whether an object controlled by a thread is the resource, or if it merely references the resource. \ No newline at end of file From 0c70ea004dfa5ad43bca38afaf708581d7f68530 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 21:12:54 +0800 Subject: [PATCH 118/524] Published with https://stackedit.io/ --- ...14\344\270\215\345\217\230\346\200\247.md" | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 "Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" diff --git "a/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" "b/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" new file mode 100644 index 0000000..b865b41 --- /dev/null +++ "b/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" @@ -0,0 +1,64 @@ +#07.线程安全和不变性 + +Race conditions occur only if multiple threads are accessing the same resource, and one or more of the threads write to the resource. If multiple threads read the same resource race conditions do not occur. + +We can make sure that objects shared between threads are never updated by any of the threads by making the shared objects immutable, and thereby thread safe. Here is an example: + +public class ImmutableValue{ + + private int value = 0; + + public ImmutableValue(int value){ + this.value = value; + } + + public int getValue(){ + return this.value; + } +} +Notice how the value for the ImmutableValue instance is passed in the constructor. Notice also how there is no setter method. Once an ImmutableValue instance is created you cannot change its value. It is immutable. You can read it however, using the getValue() method. + +If you need to perform operations on the ImmutableValue instance you can do so by returning a new instance with the value resulting from the operation. Here is an example of an add operation: + +public class ImmutableValue{ + + private int value = 0; + + public ImmutableValue(int value){ + this.value = value; + } + + public int getValue(){ + return this.value; + } + + + public ImmutableValue add(int valueToAdd){ + return new ImmutableValue(this.value + valueToAdd); + } + +} +Notice how the add() method returns a new ImmutableValue instance with the result of the add operation, rather than adding the value to itself. + +The Reference is not Thread Safe! + +It is important to remember, that even if an object is immutable and thereby thread safe, the reference to this object may not be thread safe. Look at this example: + +public class Calculator{ + private ImmutableValue currentValue = null; + + public ImmutableValue getValue(){ + return currentValue; + } + + public void setValue(ImmutableValue newValue){ + this.currentValue = newValue; + } + + public void add(int newValue){ + this.currentValue = this.currentValue.add(newValue); + } +} +The Calculator class holds a reference to an ImmutableValue instance. Notice how it is possible to change that reference through both the setValue() and add() methods. Therefore, even if the Calculator class uses an immutable object internally, it is not itself immutable, and therefore not thread safe. In other words: The ImmutableValue class is thread safe, but the use of it is not. This is something to keep in mind when trying to achieve thread safety through immutability. + +To make the Calculator class thread safe you could have declared the getValue(), setValue(), and add() methods synchronized. That would have done the trick. From ecbfe77e8e3314257587606a526a518862683699 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 21:14:33 +0800 Subject: [PATCH 119/524] Published with https://stackedit.io/ --- ...\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" "b/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" index b865b41..32f5775 100644 --- "a/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" +++ "b/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" @@ -40,7 +40,7 @@ public class ImmutableValue{ } Notice how the add() method returns a new ImmutableValue instance with the result of the add operation, rather than adding the value to itself. -The Reference is not Thread Safe! +##The Reference is not Thread Safe! It is important to remember, that even if an object is immutable and thereby thread safe, the reference to this object may not be thread safe. Look at this example: From 49fc27385eccce564ad7ad25cb95d6427945af55 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 21:16:41 +0800 Subject: [PATCH 120/524] Published with https://stackedit.io/ --- ...va\345\220\214\346\255\245\345\235\227.md" | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 "Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" new file mode 100644 index 0000000..2c76b6b --- /dev/null +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" @@ -0,0 +1,161 @@ +#08.Java同步块 + +A Java synchronized block marks a method or a block of code as synchronized. Java synchronized blocks can be used to avoid race conditions. + +The Java synchronized Keyword + +Synchronized blocks in Java are marked with the synchronized keyword. A synchronized block in Java is synchronized on some object. All synchronized blocks synchronized on the same object can only have one thread executing inside them at the same time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block. + +The synchronized keyword can be used to mark four different types of blocks: + +Instance methods +Static methods +Code blocks inside instance methods +Code blocks inside static methods +These blocks are synchronized on different objects. Which type of synchronized block you need depends on the concrete situation. + +Synchronized Instance Methods + +Here is a synchronized instance method: + + public synchronized void add(int value){ + this.count += value; + } +Notice the use of the synchronized keyword in the method declaration. This tells Java that the method is synchronized. + +A synchronized instance method in Java is synchronized on the instance (object) owning the method. Thus, each instance has its synchronized methods synchronized on a different object: the owning instance. Only one thread can execute inside a synchronized instance method. If more than one instance exist, then one thread at a time can execute inside a synchronized instance method per instance. One thread per instance. + +Synchronized Static Methods + +Static methods are marked as synchronized just like instance methods using the synchronized keyword. Here is a Java synchronized static method example: + + public static synchronized void add(int value){ + count += value; + } +Also here the synchronized keyword tells Java that the method is synchronized. + +Synchronized static methods are synchronized on the class object of the class the synchronized static method belongs to. Since only one class object exists in the Java VM per class, only one thread can execute inside a static synchronized method in the same class. + +If the static synchronized methods are located in different classes, then one thread can execute inside the static synchronized methods of each class. One thread per class regardless of which static synchronized method it calls. + +Synchronized Blocks in Instance Methods + +You do not have to synchronize a whole method. Sometimes it is preferable to synchronize only part of a method. Java synchronized blocks inside methods makes this possible. + +Here is a synchronized block of Java code inside an unsynchronized Java method: + + public void add(int value){ + + synchronized(this){ + this.count += value; + } + } +This example uses the Java synchronized block construct to mark a block of code as synchronized. This code will now execute as if it was a synchronized method. + +Notice how the Java synchronized block construct takes an object in parentheses. In the example "this" is used, which is the instance the add method is called on. The object taken in the parentheses by the synchronized construct is called a monitor object. The code is said to be synchronized on the monitor object. A synchronized instance method uses the object it belongs to as monitor object. + +Only one thread can execute inside a Java code block synchronized on the same monitor object. + +The following two examples are both synchronized on the instance they are called on. They are therefore equivalent with respect to synchronization: + + + public class MyClass { + + public synchronized void log1(String msg1, String msg2){ + log.writeln(msg1); + log.writeln(msg2); + } + + + public void log2(String msg1, String msg2){ + synchronized(this){ + log.writeln(msg1); + log.writeln(msg2); + } + } + } +Thus only a single thread can execute inside either of the two synchronized blocks in this example. + +Had the second synchronized block been synchronized on a different object than this, then one thread at a time had been able to execute inside each method. + +Synchronized Blocks in Static Methods + +Here are the same two examples as static methods. These methods are synchronized on the class object of the class the methods belong to: + + public class MyClass { + + public static synchronized void log1(String msg1, String msg2){ + log.writeln(msg1); + log.writeln(msg2); + } + + + public static void log2(String msg1, String msg2){ + synchronized(MyClass.class){ + log.writeln(msg1); + log.writeln(msg2); + } + } + } +Only one thread can execute inside any of these two methods at the same time. + +Had the second synchronized block been synchronized on a different object than MyClass.class, then one thread could execute inside each method at the same time. + +Java Synchronized Example + +Here is an example that starts 2 threads and have both of them call the add method on the same instance of Counter. Only one thread at a time will be able to call the add method on the same instance, because the method is synchronized on the instance it belongs to. + + public class Counter{ + + long count = 0; + + public synchronized void add(long value){ + this.count += value; + } + } + public class CounterThread extends Thread{ + + protected Counter counter = null; + + public CounterThread(Counter counter){ + this.counter = counter; + } + + public void run() { + for(int i=0; i<10; i++){ + counter.add(i); + } + } + } + public class Example { + + public static void main(String[] args){ + Counter counter = new Counter(); + Thread threadA = new CounterThread(counter); + Thread threadB = new CounterThread(counter); + + threadA.start(); + threadB.start(); + } + } +Two threads are created. The same Counter instance is passed to both of them in their constructor. The Counter.add() method is synchronized on the instance, because the add method is an instance method, and marked as synchronized. Therefore only one of the threads can call the add() method at a time. The other thread will wait until the first thread leaves the add() method, before it can execute the method itself. + +If the two threads had referenced two separate Counter instances, there would have been no problems calling the add() methods simultaneously. The calls would have been to different objects, so the methods called would also be synchronized on different objects (the object owning the method). Therefore the calls would not block. Here is how that could look: + + public class Example { + + public static void main(String[] args){ + Counter counterA = new Counter(); + Counter counterB = new Counter(); + Thread threadA = new CounterThread(counterA); + Thread threadB = new CounterThread(counterB); + + threadA.start(); + threadB.start(); + } + } +Notice how the two threads, threadA and threadB, no longer reference the same counter instance. The add method of counterA and counterB are synchronized on their two owning instances. Calling add() on counterA will thus not block a call to add() on counterB. + +Java Concurrency Utilities + +The synchronized mechanism was Java's first mechanism for synchronizing access to objects shared by multiple threads. The synchronized mechanism isn't very advanced though. That is why Java 5 got a whole set of concurrency utility classes to help developers implement more fine grained concurrency control than what you get with synchronized. \ No newline at end of file From 2c4aa33b7e6a97943b65d02454440afcb2e4b8c5 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 21:18:21 +0800 Subject: [PATCH 121/524] Published with https://stackedit.io/ --- ...08.Java\345\220\214\346\255\245\345\235\227.md" | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" index 2c76b6b..e86ecd1 100644 --- "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" @@ -2,7 +2,7 @@ A Java synchronized block marks a method or a block of code as synchronized. Java synchronized blocks can be used to avoid race conditions. -The Java synchronized Keyword +##The Java synchronized Keyword Synchronized blocks in Java are marked with the synchronized keyword. A synchronized block in Java is synchronized on some object. All synchronized blocks synchronized on the same object can only have one thread executing inside them at the same time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block. @@ -14,7 +14,7 @@ Code blocks inside instance methods Code blocks inside static methods These blocks are synchronized on different objects. Which type of synchronized block you need depends on the concrete situation. -Synchronized Instance Methods +##Synchronized Instance Methods Here is a synchronized instance method: @@ -25,7 +25,7 @@ Notice the use of the synchronized keyword in the method declaration. This tells A synchronized instance method in Java is synchronized on the instance (object) owning the method. Thus, each instance has its synchronized methods synchronized on a different object: the owning instance. Only one thread can execute inside a synchronized instance method. If more than one instance exist, then one thread at a time can execute inside a synchronized instance method per instance. One thread per instance. -Synchronized Static Methods +##Synchronized Static Methods Static methods are marked as synchronized just like instance methods using the synchronized keyword. Here is a Java synchronized static method example: @@ -38,7 +38,7 @@ Synchronized static methods are synchronized on the class object of the class th If the static synchronized methods are located in different classes, then one thread can execute inside the static synchronized methods of each class. One thread per class regardless of which static synchronized method it calls. -Synchronized Blocks in Instance Methods +##Synchronized Blocks in Instance Methods You do not have to synchronize a whole method. Sometimes it is preferable to synchronize only part of a method. Java synchronized blocks inside methods makes this possible. @@ -78,7 +78,7 @@ Thus only a single thread can execute inside either of the two synchronized bloc Had the second synchronized block been synchronized on a different object than this, then one thread at a time had been able to execute inside each method. -Synchronized Blocks in Static Methods +##Synchronized Blocks in Static Methods Here are the same two examples as static methods. These methods are synchronized on the class object of the class the methods belong to: @@ -101,7 +101,7 @@ Only one thread can execute inside any of these two methods at the same time. Had the second synchronized block been synchronized on a different object than MyClass.class, then one thread could execute inside each method at the same time. -Java Synchronized Example +##Java Synchronized Example Here is an example that starts 2 threads and have both of them call the add method on the same instance of Counter. Only one thread at a time will be able to call the add method on the same instance, because the method is synchronized on the instance it belongs to. @@ -156,6 +156,6 @@ If the two threads had referenced two separate Counter instances, there would ha } Notice how the two threads, threadA and threadB, no longer reference the same counter instance. The add method of counterA and counterB are synchronized on their two owning instances. Calling add() on counterA will thus not block a call to add() on counterB. -Java Concurrency Utilities +##Java Concurrency Utilities The synchronized mechanism was Java's first mechanism for synchronizing access to objects shared by multiple threads. The synchronized mechanism isn't very advanced though. That is why Java 5 got a whole set of concurrency utility classes to help developers implement more fine grained concurrency control than what you get with synchronized. \ No newline at end of file From f5e563fb51c8b750debb9db3091f2b8fba14ddc4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 21:20:50 +0800 Subject: [PATCH 122/524] Published with https://stackedit.io/ --- ...va\345\220\214\346\255\245\345\235\227.md" | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" index e86ecd1..e3e6196 100644 --- "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" @@ -18,9 +18,12 @@ These blocks are synchronized on different objects. Which type of synchronized b Here is a synchronized instance method: +```Java public synchronized void add(int value){ this.count += value; } +``` + Notice the use of the synchronized keyword in the method declaration. This tells Java that the method is synchronized. A synchronized instance method in Java is synchronized on the instance (object) owning the method. Thus, each instance has its synchronized methods synchronized on a different object: the owning instance. Only one thread can execute inside a synchronized instance method. If more than one instance exist, then one thread at a time can execute inside a synchronized instance method per instance. One thread per instance. @@ -29,9 +32,12 @@ A synchronized instance method in Java is synchronized on the instance (object) Static methods are marked as synchronized just like instance methods using the synchronized keyword. Here is a Java synchronized static method example: +```Java public static synchronized void add(int value){ count += value; } +``` + Also here the synchronized keyword tells Java that the method is synchronized. Synchronized static methods are synchronized on the class object of the class the synchronized static method belongs to. Since only one class object exists in the Java VM per class, only one thread can execute inside a static synchronized method in the same class. @@ -44,12 +50,15 @@ You do not have to synchronize a whole method. Sometimes it is preferable to syn Here is a synchronized block of Java code inside an unsynchronized Java method: +```Java public void add(int value){ synchronized(this){ this.count += value; } } +``` + This example uses the Java synchronized block construct to mark a block of code as synchronized. This code will now execute as if it was a synchronized method. Notice how the Java synchronized block construct takes an object in parentheses. In the example "this" is used, which is the instance the add method is called on. The object taken in the parentheses by the synchronized construct is called a monitor object. The code is said to be synchronized on the monitor object. A synchronized instance method uses the object it belongs to as monitor object. @@ -58,7 +67,7 @@ Only one thread can execute inside a Java code block synchronized on the same mo The following two examples are both synchronized on the instance they are called on. They are therefore equivalent with respect to synchronization: - +```Java public class MyClass { public synchronized void log1(String msg1, String msg2){ @@ -74,6 +83,8 @@ The following two examples are both synchronized on the instance they are called } } } +``` + Thus only a single thread can execute inside either of the two synchronized blocks in this example. Had the second synchronized block been synchronized on a different object than this, then one thread at a time had been able to execute inside each method. @@ -82,6 +93,7 @@ Had the second synchronized block been synchronized on a different object than t Here are the same two examples as static methods. These methods are synchronized on the class object of the class the methods belong to: +```Java public class MyClass { public static synchronized void log1(String msg1, String msg2){ @@ -97,6 +109,8 @@ Here are the same two examples as static methods. These methods are synchronized } } } +``` + Only one thread can execute inside any of these two methods at the same time. Had the second synchronized block been synchronized on a different object than MyClass.class, then one thread could execute inside each method at the same time. @@ -105,6 +119,7 @@ Had the second synchronized block been synchronized on a different object than M Here is an example that starts 2 threads and have both of them call the add method on the same instance of Counter. Only one thread at a time will be able to call the add method on the same instance, because the method is synchronized on the instance it belongs to. +```Java public class Counter{ long count = 0; @@ -138,10 +153,13 @@ Here is an example that starts 2 threads and have both of them call the add meth threadB.start(); } } +``` + Two threads are created. The same Counter instance is passed to both of them in their constructor. The Counter.add() method is synchronized on the instance, because the add method is an instance method, and marked as synchronized. Therefore only one of the threads can call the add() method at a time. The other thread will wait until the first thread leaves the add() method, before it can execute the method itself. If the two threads had referenced two separate Counter instances, there would have been no problems calling the add() methods simultaneously. The calls would have been to different objects, so the methods called would also be synchronized on different objects (the object owning the method). Therefore the calls would not block. Here is how that could look: +```Java public class Example { public static void main(String[] args){ @@ -154,6 +172,8 @@ If the two threads had referenced two separate Counter instances, there would ha threadB.start(); } } +``` + Notice how the two threads, threadA and threadB, no longer reference the same counter instance. The add method of counterA and counterB are synchronized on their two owning instances. Calling add() on counterA will thus not block a call to add() on counterB. ##Java Concurrency Utilities From 5769ab676127cff8ec99e95ea0248b673209abe5 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 21:22:57 +0800 Subject: [PATCH 123/524] Published with https://stackedit.io/ --- ...6\350\265\204\346\272\220\345\205\261\344\272\253.md" | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" index a63c446..17ea14e 100644 --- "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" +++ "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" @@ -86,8 +86,9 @@ check if record X exists if not, insert record X If two threads execute this simultanously, and the record X they are checking for happens to be the same record, there is a risk that both of the threads end up inserting it. This is how: -Thread 1 checks if record X exists. Result = no -Thread 2 checks if record X exists. Result = no -Thread 1 inserts record X -Thread 2 inserts record X +> Thread 1 checks if record X exists. Result = no +> Thread 2 checks if record X exists. Result = no +> Thread 1 inserts record X +> Thread 2 inserts record X + This could also happen with threads operating on files or other shared resources. Therefore it is important to distinguish between whether an object controlled by a thread is the resource, or if it merely references the resource. \ No newline at end of file From 138a0ec077abe669cc9c4bcb0d5d08aeda512de2 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 22:56:03 +0800 Subject: [PATCH 124/524] Published with https://stackedit.io/ --- ...04\346\272\220\345\205\261\344\272\253.md" | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" index 17ea14e..432d4dc 100644 --- "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" +++ "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" @@ -1,24 +1,29 @@ #06.线程安全与资源共享(Thread Safety and Shared Resources) -Code that is safe to call by multiple threads simultanously is called thread safe. If a piece of code is thread safe, then it contains no race conditions. Race condition only occur when multiple threads update shared resources. Therefore it is important to know what resources Java threads share when executing. + +如果一段代码可以安全地由多个线程并行调用,则称这段代码是**线程安全**的。如果一段代码是线程安全的,则这段代码不会引起**资源竞争**。只有当多个线程更新共享资源时才会发生**资源竞争**问题。因此,重要是要知道程序执行过程中哪些资源是线程共享的。 ##局部变量(Local Variables) -Local variables are stored in each thread's own stack. That means that local variables are never shared between threads. That also means that all local primitive variables are thread safe. Here is an example of a thread safe local primitive variable: +局部变量存储在各自线程的栈中,这意味着局部变量不是线程共享的,这同样意味着所有的局部基本类型变量都是线程安全的。如下代码代码线程安全的: +```Java public void someMethod(){ long threadSafeInt = 0; threadSafeInt++; } +``` -## 本地变量引用(Local Object References) +## 局部对象引用(Local Object References) -Local references to objects are a bit different. The reference itself is not shared. The object referenced however, is not stored in each threads's local stack. All objects are stored in the shared heap. If an object created locally never escapes the method it was created in, it is thread safe. In fact you can also pass it on to other methods and objects as long as none of these methods or objects make the passed object available to other threads. Here is an example of a thread safe local object: + 局部对象的引用有一些差异。引用本身是不同享的,然而,引用的对象并不是存储在线程栈中,所有的对象都存储在Java堆,如果一个对象始终不逃逸出创建它的方法作用域之外,则它是线程安全的(If an object created locally never escapes the method it was created in, it is thread safe. )。而实际上,你也可以把这个对象引用传递给其他对象或者方法,只要传递的对象没有被其他线程处理,则它也是线程安全的。 -public void someMethod(){ +下面这个例子中的局部对象是线程安全的: +```Java +public void someMethod(){ LocalObject localObject = new LocalObject(); localObject.callMethod(); @@ -28,14 +33,17 @@ public void someMethod(){ public void method2(LocalObject localObject){ localObject.setValue("value"); } +``` + +在这个例子中,LocalObject的实例并没有从`someMethod()`方法中返回,也没有传递给其他在`someMethod()`作用域外的对象。每个执行`someMethod()`的线程都会创建各自的LocalObject实例,然后将引用传递给localObject引用变量。因此,这里的LocalObject的使用是线程安全的,实际上,整个`someMethod()`方法都是线程安全的,即使LocalObject实例作为参数传给本身对象或其他对象的方法,它都是线程安全的。唯一意外的情况就是:当localObject传递给其他的方法,而这些方法是可以被多线程访问的,则会导致线程安全问题。 -The LocalObject instance in this example is not returned from the method, nor is it passed to any other objects that are accessible from outside the someMethod() method. Each thread executing the someMethod() method will create its own LocalObject instance and assign it to the localObject reference. Therefore the use of the LocalObject here is thread safe. In fact, the whole method someMethod() is thread safe. Even if the LocalObject instance is passed as parameter to other methods in the same class, or in other classes, the use of it is thread safe. The only exception is of course, if one of the methods called with the LocalObject as parameter, stores the LocalObject instance in a way that allows access to it from other threads. -##对象成员(Object Members) +##对象成员变量(Object Members) -Object members are stored on the heap along with the object. Therefore, if two threads call a method on the same object instance and this method updates object members, the method is not thread safe. Here is an example of a method that is not thread safe: +对象的成员变量跟随对象本身存储在Java共享堆中。因此,如果两个变量调用同一个对象的一个方法,而这个方法会对对象的成员变量进行修改,则这个方法是**线程不安全**的。如下面这个例子: +```Java public class NotThreadSafe{ StringBuilder builder = new StringBuilder(); @@ -43,9 +51,11 @@ public class NotThreadSafe{ this.builder.append(text); } } -If two threads call the add() method simultanously on the same NotThreadSafe instance then it leads to race conditions. For instance: +``` +如果两个线程同时调用同一个NotThreadSafe实例的`add(String texty)`方法,则会导致资源竞争: +```Java NotThreadSafe sharedInstance = new NotThreadSafe(); new Thread(new MyRunnable(sharedInstance)).start(); @@ -62,15 +72,22 @@ public class MyRunnable implements Runnable{ this.instance.add("some text"); } } -Notice how the two MyRunnable instances share the same NotThreadSafe instance. Therefore, when they call the add() method on the NotThreadSafe instance it leads to race condition. +``` -However, if two threads call the add() method simultanously on different instances then it does not lead to race condition. Here is the example from before, but slightly modified: +注意两个MyRunnable实例共享同一个NoThreadSafe实例。因此,当两个线程同时调用`add()` 方法时则会导致资源竞争。 +然而,如果两个线程同时调用不同NoThreadSafe实例的`add()`方法则不会导致资源竞争。如下面这个例子: + + +```Java new Thread(new MyRunnable(new NotThreadSafe())).start(); new Thread(new MyRunnable(new NotThreadSafe())).start(); -Now the two threads have each their own instance of NotThreadSafe so their calls to the add method doesn't interfere with each other. The code does not have race condition anymore. So, even if an object is not thread safe it can still be used in a way that doesn't lead to race condition. +``` + +现在两个线程都拥有各自的NoThreadSafe实例,它们调用`add()`方法时并不会互相干扰,所以并没有导致资源竞争。因此,即使一个对象不是线程安全的,它们也可以用在不会引起资源竞争的代码中。 + -##The Thread Control Escape Rule +##The Thread Control Escape Rule(线程控制逃逸规则) When trying to determine if your code's access of a certain resource is thread safe you can use the thread control escape rule: From 5aaefb298e85bb36845093327570e7ca22f3f8ff Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 23:06:58 +0800 Subject: [PATCH 125/524] Published with https://stackedit.io/ --- ...5\204\346\272\220\345\205\261\344\272\253.md" | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" index 432d4dc..dc6955c 100644 --- "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" +++ "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" @@ -89,18 +89,20 @@ new Thread(new MyRunnable(new NotThreadSafe())).start(); ##The Thread Control Escape Rule(线程控制逃逸规则) -When trying to determine if your code's access of a certain resource is thread safe you can use the thread control escape rule: +如果想知道你的代码是否线程安全,可以使用以下规则: + +> 如果一个资源的创建和使用始终在同一个线程的控制下,并且从没有逃逸出这个线程的控制,则认为是线程安全的。 + + +>If a resource is created, used and disposed within the control of the same thread, and never escapes the control of this thread, the use of that resource is thread safe. -If a resource is created, used and disposed within -the control of the same thread, -and never escapes the control of this thread, -the use of that resource is thread safe. Resources can be any shared resource like an object, array, file, database connection, socket etc. In Java you do not always explicitly dispose objects, so "disposed" means losing or null'ing the reference to the object. Even if the use of an object is thread safe, if that object points to a shared resource like a file or database, your application as a whole may not be thread safe. For instance, if thread 1 and thread 2 each create their own database connections, connection 1 and connection 2, the use of each connection itself is thread safe. But the use of the database the connections point to may not be thread safe. For example, if both threads execute code like this: -check if record X exists -if not, insert record X +> check if record X exists +> if not, insert record X + If two threads execute this simultanously, and the record X they are checking for happens to be the same record, there is a risk that both of the threads end up inserting it. This is how: > Thread 1 checks if record X exists. Result = no From 5fdda034dd21810cbe1f7f2980e22ad7ef1b621d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 23:08:04 +0800 Subject: [PATCH 126/524] Published with https://stackedit.io/ --- ...5\204\346\272\220\345\205\261\344\272\253.md" | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" index dc6955c..c3c6c05 100644 --- "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" +++ "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" @@ -100,14 +100,18 @@ Resources can be any shared resource like an object, array, file, database conne Even if the use of an object is thread safe, if that object points to a shared resource like a file or database, your application as a whole may not be thread safe. For instance, if thread 1 and thread 2 each create their own database connections, connection 1 and connection 2, the use of each connection itself is thread safe. But the use of the database the connections point to may not be thread safe. For example, if both threads execute code like this: -> check if record X exists -> if not, insert record X +```txt +check if record X exists +if not, insert record X +``` If two threads execute this simultanously, and the record X they are checking for happens to be the same record, there is a risk that both of the threads end up inserting it. This is how: -> Thread 1 checks if record X exists. Result = no -> Thread 2 checks if record X exists. Result = no -> Thread 1 inserts record X -> Thread 2 inserts record X +```txt +Thread 1 checks if record X exists. Result = no +Thread 2 checks if record X exists. Result = no +Thread 1 inserts record X +Thread 2 inserts record X +``` This could also happen with threads operating on files or other shared resources. Therefore it is important to distinguish between whether an object controlled by a thread is the resource, or if it merely references the resource. \ No newline at end of file From 5f856a296f0d35f1942bfd0cb24bb1a02d0d4923 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 11 Sep 2014 23:11:10 +0800 Subject: [PATCH 127/524] Published with https://stackedit.io/ --- ...70\216\350\265\204\346\272\220\345\205\261\344\272\253.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" index c3c6c05..cacbcbe 100644 --- "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" +++ "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" @@ -100,14 +100,14 @@ Resources can be any shared resource like an object, array, file, database conne Even if the use of an object is thread safe, if that object points to a shared resource like a file or database, your application as a whole may not be thread safe. For instance, if thread 1 and thread 2 each create their own database connections, connection 1 and connection 2, the use of each connection itself is thread safe. But the use of the database the connections point to may not be thread safe. For example, if both threads execute code like this: -```txt +``` check if record X exists if not, insert record X ``` If two threads execute this simultanously, and the record X they are checking for happens to be the same record, there is a risk that both of the threads end up inserting it. This is how: -```txt +``` Thread 1 checks if record X exists. Result = no Thread 2 checks if record X exists. Result = no Thread 1 inserts record X From 838e210e1a59cb83308e02ee0ec04e4c8a819a54 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 00:36:44 +0800 Subject: [PATCH 128/524] Published with https://stackedit.io/ --- ...250\345\222\214\344\270\215\345\217\230\346\200\247.md" | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" "b/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" index 32f5775..8918592 100644 --- "a/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" +++ "b/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" @@ -1,9 +1,10 @@ #07.线程安全和不变性 -Race conditions occur only if multiple threads are accessing the same resource, and one or more of the threads write to the resource. If multiple threads read the same resource race conditions do not occur. +只有当多个线程访问共享资源,并且一个线程或多个线程对资源进行写操作时,才会发生资源竞争。如果多个线程同时只对共享资源进行读操作,则不会发生资源竞争。 -We can make sure that objects shared between threads are never updated by any of the threads by making the shared objects immutable, and thereby thread safe. Here is an example: +我们可以通过把共享对象设置为不可变以至于让线程不能对对象进行改动,从而保证了线程安全。如下面这个例子: +```Java public class ImmutableValue{ private int value = 0; @@ -16,6 +17,8 @@ public class ImmutableValue{ return this.value; } } +``` + Notice how the value for the ImmutableValue instance is passed in the constructor. Notice also how there is no setter method. Once an ImmutableValue instance is created you cannot change its value. It is immutable. You can read it however, using the getValue() method. If you need to perform operations on the ImmutableValue instance you can do so by returning a new instance with the value resulting from the operation. Here is an example of an add operation: From 1d553539a6d52f94ccc82ecd515ac3c7e5cb5106 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 01:10:05 +0800 Subject: [PATCH 129/524] Published with https://stackedit.io/ --- ...14\344\270\215\345\217\230\346\200\247.md" | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git "a/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" "b/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" index 8918592..9352541 100644 --- "a/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" +++ "b/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" @@ -19,10 +19,12 @@ public class ImmutableValue{ } ``` -Notice how the value for the ImmutableValue instance is passed in the constructor. Notice also how there is no setter method. Once an ImmutableValue instance is created you cannot change its value. It is immutable. You can read it however, using the getValue() method. +注意value的值是通过构造函数进行设置的,并且value没有提供setter方法,所以一旦ImmutableValue实例被创建后,value的值就不能进行更改了。可以通过`getValue()`获取value的值,但不能进行改动。 -If you need to perform operations on the ImmutableValue instance you can do so by returning a new instance with the value resulting from the operation. Here is an example of an add operation: +如果想要对ImmutableValue对象进行操作,可以通过返回一个新的实例来完成。例如下面这个 + +```Java public class ImmutableValue{ private int value = 0; @@ -34,19 +36,21 @@ public class ImmutableValue{ public int getValue(){ return this.value; } - - public ImmutableValue add(int valueToAdd){ - return new ImmutableValue(this.value + valueToAdd); - } + public ImmutableValue add(int valueToAdd){ + return new ImmutableValue(this.value + valueToAdd); + } } -Notice how the add() method returns a new ImmutableValue instance with the result of the add operation, rather than adding the value to itself. +``` -##The Reference is not Thread Safe! +注意这里返回了一个新的ImmutableValue实例,而不是对value的值进行修改。 -It is important to remember, that even if an object is immutable and thereby thread safe, the reference to this object may not be thread safe. Look at this example: +##引用不是线程安全的!(The Reference is not Thread Safe!) +有一点需要谨记:**即使一个对象是线程安全的不可变对象,指向这个对象的引用也可能不是线程安全的。** + +```Java public class Calculator{ private ImmutableValue currentValue = null; @@ -62,6 +66,8 @@ public class Calculator{ this.currentValue = this.currentValue.add(newValue); } } +``` + The Calculator class holds a reference to an ImmutableValue instance. Notice how it is possible to change that reference through both the setValue() and add() methods. Therefore, even if the Calculator class uses an immutable object internally, it is not itself immutable, and therefore not thread safe. In other words: The ImmutableValue class is thread safe, but the use of it is not. This is something to keep in mind when trying to achieve thread safety through immutability. To make the Calculator class thread safe you could have declared the getValue(), setValue(), and add() methods synchronized. That would have done the trick. From 98aa8de252436336dc7f19c620133e75d8c8eaf4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 01:16:52 +0800 Subject: [PATCH 130/524] Published with https://stackedit.io/ --- ...\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" "b/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" index 9352541..1264207 100644 --- "a/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" +++ "b/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" @@ -1,6 +1,6 @@ #07.线程安全和不变性 -只有当多个线程访问共享资源,并且一个线程或多个线程对资源进行写操作时,才会发生资源竞争。如果多个线程同时只对共享资源进行读操作,则不会发生资源竞争。 +只有当多个线程访问共享资源,并且一个线程或多个线程对资源进行写操作时,才会发生竞态条件。如果多个线程同时只对共享资源进行读操作,则不会发生**竞态条件**。 我们可以通过把共享对象设置为不可变以至于让线程不能对对象进行改动,从而保证了线程安全。如下面这个例子: From 91efbf3473d72db16c295eca48d9f540bd9d3ae1 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 01:17:23 +0800 Subject: [PATCH 131/524] Published with https://stackedit.io/ --- ...350\265\204\346\272\220\345\205\261\344\272\253.md" | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" index cacbcbe..96a66b9 100644 --- "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" +++ "b/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" @@ -1,7 +1,7 @@ #06.线程安全与资源共享(Thread Safety and Shared Resources) -如果一段代码可以安全地由多个线程并行调用,则称这段代码是**线程安全**的。如果一段代码是线程安全的,则这段代码不会引起**资源竞争**。只有当多个线程更新共享资源时才会发生**资源竞争**问题。因此,重要是要知道程序执行过程中哪些资源是线程共享的。 +如果一段代码可以安全地由多个线程并行调用,则称这段代码是**线程安全**的。如果一段代码是线程安全的,则这段代码不会引起**竞态条件**。只有当多个线程更新共享资源时才会发生**竞态条件**问题。因此,重要是要知道程序执行过程中哪些资源是线程共享的。 ##局部变量(Local Variables) @@ -53,7 +53,7 @@ public class NotThreadSafe{ } ``` -如果两个线程同时调用同一个NotThreadSafe实例的`add(String texty)`方法,则会导致资源竞争: +如果两个线程同时调用同一个NotThreadSafe实例的`add(String texty)`方法,则会导致竞态条件: ```Java NotThreadSafe sharedInstance = new NotThreadSafe(); @@ -74,9 +74,9 @@ public class MyRunnable implements Runnable{ } ``` -注意两个MyRunnable实例共享同一个NoThreadSafe实例。因此,当两个线程同时调用`add()` 方法时则会导致资源竞争。 +注意两个MyRunnable实例共享同一个NoThreadSafe实例。因此,当两个线程同时调用`add()` 方法时则会导致竞态条件。 -然而,如果两个线程同时调用不同NoThreadSafe实例的`add()`方法则不会导致资源竞争。如下面这个例子: +然而,如果两个线程同时调用不同NoThreadSafe实例的`add()`方法则不会导致竞态条件。如下面这个例子: ```Java @@ -84,7 +84,7 @@ new Thread(new MyRunnable(new NotThreadSafe())).start(); new Thread(new MyRunnable(new NotThreadSafe())).start(); ``` -现在两个线程都拥有各自的NoThreadSafe实例,它们调用`add()`方法时并不会互相干扰,所以并没有导致资源竞争。因此,即使一个对象不是线程安全的,它们也可以用在不会引起资源竞争的代码中。 +现在两个线程都拥有各自的NoThreadSafe实例,它们调用`add()`方法时并不会互相干扰,所以并没有导致竞态条件。因此,即使一个对象不是线程安全的,它们也可以用在不会引起竞态条件的代码中。 ##The Thread Control Escape Rule(线程控制逃逸规则) From 235f4610402cc45bffe3fae827002fa56a2f88af Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 01:19:04 +0800 Subject: [PATCH 132/524] =?UTF-8?q?Update=20and=20rename=2005.=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E7=AB=9E=E4=BA=89=E5=92=8C=E4=B8=B4=E7=95=8C=E5=8C=BA?= =?UTF-8?q?.md=20to=2005.=E7=AB=9E=E6=80=81=E6=9D=A1=E4=BB=B6=E5=92=8C?= =?UTF-8?q?=E4=B8=B4=E7=95=8C=E5=8C=BA.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\266\345\222\214\344\270\264\347\225\214\345\214\272.md" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename "Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" => "Java-Concurrency-Multithreading/05.\347\253\236\346\200\201\346\235\241\344\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" (86%) diff --git "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" "b/Java-Concurrency-Multithreading/05.\347\253\236\346\200\201\346\235\241\344\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" similarity index 86% rename from "Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" rename to "Java-Concurrency-Multithreading/05.\347\253\236\346\200\201\346\235\241\344\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" index 9294181..3aa7154 100644 --- "a/Java-Concurrency-Multithreading/05.\350\265\204\346\272\220\347\253\236\344\272\211\345\222\214\344\270\264\347\225\214\345\214\272.md" +++ "b/Java-Concurrency-Multithreading/05.\347\253\236\346\200\201\346\235\241\344\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" @@ -1,5 +1,5 @@ -#资源竞争和临界区(Race Conditions and Critical Sections) +#05.竞态条件和临界区(Race Conditions and Critical Sections) 在一个应用程序中运行多个线程这本身不会导致什么问题。问题在于多个线程同时对同一资源进行存取,例如同样的内存空间(变量、数组或对象),系统资源(数据库,文件系统等等)。如果是多个线程对同一资源进行读取,则不会有任何问题。 @@ -39,8 +39,8 @@ A: writes register value (3) back to memory. this.count now equals 3 -## 资源竞争和临界点(Race Conditions & Critical Sections) +## 竞态条件和临界点(Race Conditions & Critical Sections) -当多个线程对同一个资源进行竞争,访问这个资源的顺序是非常重要的,称之为**资源竞争**(he situation where two threads compete for the same resource, where the sequence in which the resource is accessed is significant, is called race conditions)。可以引起资源竞争的代码区域,称之为**临界区**。在前面的示例中,`add()`方法就是一个临界区。资源竞争可以通过在临界区进行适当的**线程同步**来避免。 +当多个线程对同一个资源进行竞争,访问这个资源的顺序是非常重要的,称之为**竞态条件**(he situation where two threads compete for the same resource, where the sequence in which the resource is accessed is significant, is called race conditions)。可以引起竞态条件的代码区域,称之为**临界区**。在前面的示例中,`add()`方法就是一个临界区。竞态条件可以通过在临界区进行适当的**线程同步**来避免。 From 2bcc9a91620ec1c1d93fa9fec93939f77a08a041 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 01:22:29 +0800 Subject: [PATCH 133/524] Published with https://stackedit.io/ --- ...8.Java\345\220\214\346\255\245\345\235\227.md" | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" index e3e6196..a8276ea 100644 --- "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" @@ -2,7 +2,10 @@ A Java synchronized block marks a method or a block of code as synchronized. Java synchronized blocks can be used to avoid race conditions. -##The Java synchronized Keyword +Java synchronized block(Java同步块)用来对方法或代码块进行标记,表明这个方法或代码块是同步的。Java同步块可以避免**竞态条件**。 + + +##synchronized关键字(The Java synchronized Keyword) Synchronized blocks in Java are marked with the synchronized keyword. A synchronized block in Java is synchronized on some object. All synchronized blocks synchronized on the same object can only have one thread executing inside them at the same time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block. @@ -14,7 +17,7 @@ Code blocks inside instance methods Code blocks inside static methods These blocks are synchronized on different objects. Which type of synchronized block you need depends on the concrete situation. -##Synchronized Instance Methods +##同步实例方法(Synchronized Instance Methods) Here is a synchronized instance method: @@ -28,7 +31,7 @@ Notice the use of the synchronized keyword in the method declaration. This tells A synchronized instance method in Java is synchronized on the instance (object) owning the method. Thus, each instance has its synchronized methods synchronized on a different object: the owning instance. Only one thread can execute inside a synchronized instance method. If more than one instance exist, then one thread at a time can execute inside a synchronized instance method per instance. One thread per instance. -##Synchronized Static Methods +##同步静态方法(Synchronized Static Methods) Static methods are marked as synchronized just like instance methods using the synchronized keyword. Here is a Java synchronized static method example: @@ -44,7 +47,7 @@ Synchronized static methods are synchronized on the class object of the class th If the static synchronized methods are located in different classes, then one thread can execute inside the static synchronized methods of each class. One thread per class regardless of which static synchronized method it calls. -##Synchronized Blocks in Instance Methods +##实例方法中的同步块(Synchronized Blocks in Instance Methods) You do not have to synchronize a whole method. Sometimes it is preferable to synchronize only part of a method. Java synchronized blocks inside methods makes this possible. @@ -89,7 +92,7 @@ Thus only a single thread can execute inside either of the two synchronized bloc Had the second synchronized block been synchronized on a different object than this, then one thread at a time had been able to execute inside each method. -##Synchronized Blocks in Static Methods +##静态方法中的同步块(Synchronized Blocks in Static Methods) Here are the same two examples as static methods. These methods are synchronized on the class object of the class the methods belong to: @@ -115,7 +118,7 @@ Only one thread can execute inside any of these two methods at the same time. Had the second synchronized block been synchronized on a different object than MyClass.class, then one thread could execute inside each method at the same time. -##Java Synchronized Example +##Java同步示例(Java Synchronized Example) Here is an example that starts 2 threads and have both of them call the add method on the same instance of Counter. Only one thread at a time will be able to call the add method on the same instance, because the method is synchronized on the instance it belongs to. From 91680c3828959580c8ad0a910e52f72b245551c4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 01:44:13 +0800 Subject: [PATCH 134/524] Published with https://stackedit.io/ --- ...8.Java\345\220\214\346\255\245\345\235\227.md" | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" index a8276ea..40668d6 100644 --- "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" @@ -7,15 +7,16 @@ Java synchronized block(Java同步块)用来对方法或代码块进行标 ##synchronized关键字(The Java synchronized Keyword) -Synchronized blocks in Java are marked with the synchronized keyword. A synchronized block in Java is synchronized on some object. All synchronized blocks synchronized on the same object can only have one thread executing inside them at the same time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block. +Java中的同步块使用关键字**synchronized**进行标记**。同步块在Java中是同步在某个对象上。所有同步在一个对象上的同步块在同一时间只能被一个线程进入并执行里面的代码。**其他所有试图进入该对象同步块的线程将被阻塞,直到执行该同步块中的线程退出。 -The synchronized keyword can be used to mark four different types of blocks: +**synchronized**关键字可以被用于标记以下四种不同类型的块: -Instance methods -Static methods -Code blocks inside instance methods -Code blocks inside static methods -These blocks are synchronized on different objects. Which type of synchronized block you need depends on the concrete situation. +- 实例方法(Instance methods) +- 静态方法(Static methods) +- 实例方法中的代码块(Code blocks inside instance methods) +- 静态方法中的代码块(Code blocks inside static methods) + +上述同步块都同步在不同对象上。实际需要那种同步块视具体情况而定。 ##同步实例方法(Synchronized Instance Methods) From a62051a7e6dd1bc6c70ca12a846947170048dfed Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 09:52:09 +0800 Subject: [PATCH 135/524] Published with https://stackedit.io/ --- ....Java\345\220\214\346\255\245\345\235\227" | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 "Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" new file mode 100644 index 0000000..40668d6 --- /dev/null +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" @@ -0,0 +1,185 @@ +#08.Java同步块 + +A Java synchronized block marks a method or a block of code as synchronized. Java synchronized blocks can be used to avoid race conditions. + +Java synchronized block(Java同步块)用来对方法或代码块进行标记,表明这个方法或代码块是同步的。Java同步块可以避免**竞态条件**。 + + +##synchronized关键字(The Java synchronized Keyword) + +Java中的同步块使用关键字**synchronized**进行标记**。同步块在Java中是同步在某个对象上。所有同步在一个对象上的同步块在同一时间只能被一个线程进入并执行里面的代码。**其他所有试图进入该对象同步块的线程将被阻塞,直到执行该同步块中的线程退出。 + +**synchronized**关键字可以被用于标记以下四种不同类型的块: + +- 实例方法(Instance methods) +- 静态方法(Static methods) +- 实例方法中的代码块(Code blocks inside instance methods) +- 静态方法中的代码块(Code blocks inside static methods) + +上述同步块都同步在不同对象上。实际需要那种同步块视具体情况而定。 + +##同步实例方法(Synchronized Instance Methods) + +Here is a synchronized instance method: + +```Java + public synchronized void add(int value){ + this.count += value; + } +``` + +Notice the use of the synchronized keyword in the method declaration. This tells Java that the method is synchronized. + +A synchronized instance method in Java is synchronized on the instance (object) owning the method. Thus, each instance has its synchronized methods synchronized on a different object: the owning instance. Only one thread can execute inside a synchronized instance method. If more than one instance exist, then one thread at a time can execute inside a synchronized instance method per instance. One thread per instance. + +##同步静态方法(Synchronized Static Methods) + +Static methods are marked as synchronized just like instance methods using the synchronized keyword. Here is a Java synchronized static method example: + +```Java + public static synchronized void add(int value){ + count += value; + } +``` + +Also here the synchronized keyword tells Java that the method is synchronized. + +Synchronized static methods are synchronized on the class object of the class the synchronized static method belongs to. Since only one class object exists in the Java VM per class, only one thread can execute inside a static synchronized method in the same class. + +If the static synchronized methods are located in different classes, then one thread can execute inside the static synchronized methods of each class. One thread per class regardless of which static synchronized method it calls. + +##实例方法中的同步块(Synchronized Blocks in Instance Methods) + +You do not have to synchronize a whole method. Sometimes it is preferable to synchronize only part of a method. Java synchronized blocks inside methods makes this possible. + +Here is a synchronized block of Java code inside an unsynchronized Java method: + +```Java + public void add(int value){ + + synchronized(this){ + this.count += value; + } + } +``` + +This example uses the Java synchronized block construct to mark a block of code as synchronized. This code will now execute as if it was a synchronized method. + +Notice how the Java synchronized block construct takes an object in parentheses. In the example "this" is used, which is the instance the add method is called on. The object taken in the parentheses by the synchronized construct is called a monitor object. The code is said to be synchronized on the monitor object. A synchronized instance method uses the object it belongs to as monitor object. + +Only one thread can execute inside a Java code block synchronized on the same monitor object. + +The following two examples are both synchronized on the instance they are called on. They are therefore equivalent with respect to synchronization: + +```Java + public class MyClass { + + public synchronized void log1(String msg1, String msg2){ + log.writeln(msg1); + log.writeln(msg2); + } + + + public void log2(String msg1, String msg2){ + synchronized(this){ + log.writeln(msg1); + log.writeln(msg2); + } + } + } +``` + +Thus only a single thread can execute inside either of the two synchronized blocks in this example. + +Had the second synchronized block been synchronized on a different object than this, then one thread at a time had been able to execute inside each method. + +##静态方法中的同步块(Synchronized Blocks in Static Methods) + +Here are the same two examples as static methods. These methods are synchronized on the class object of the class the methods belong to: + +```Java + public class MyClass { + + public static synchronized void log1(String msg1, String msg2){ + log.writeln(msg1); + log.writeln(msg2); + } + + + public static void log2(String msg1, String msg2){ + synchronized(MyClass.class){ + log.writeln(msg1); + log.writeln(msg2); + } + } + } +``` + +Only one thread can execute inside any of these two methods at the same time. + +Had the second synchronized block been synchronized on a different object than MyClass.class, then one thread could execute inside each method at the same time. + +##Java同步示例(Java Synchronized Example) + +Here is an example that starts 2 threads and have both of them call the add method on the same instance of Counter. Only one thread at a time will be able to call the add method on the same instance, because the method is synchronized on the instance it belongs to. + +```Java + public class Counter{ + + long count = 0; + + public synchronized void add(long value){ + this.count += value; + } + } + public class CounterThread extends Thread{ + + protected Counter counter = null; + + public CounterThread(Counter counter){ + this.counter = counter; + } + + public void run() { + for(int i=0; i<10; i++){ + counter.add(i); + } + } + } + public class Example { + + public static void main(String[] args){ + Counter counter = new Counter(); + Thread threadA = new CounterThread(counter); + Thread threadB = new CounterThread(counter); + + threadA.start(); + threadB.start(); + } + } +``` + +Two threads are created. The same Counter instance is passed to both of them in their constructor. The Counter.add() method is synchronized on the instance, because the add method is an instance method, and marked as synchronized. Therefore only one of the threads can call the add() method at a time. The other thread will wait until the first thread leaves the add() method, before it can execute the method itself. + +If the two threads had referenced two separate Counter instances, there would have been no problems calling the add() methods simultaneously. The calls would have been to different objects, so the methods called would also be synchronized on different objects (the object owning the method). Therefore the calls would not block. Here is how that could look: + +```Java + public class Example { + + public static void main(String[] args){ + Counter counterA = new Counter(); + Counter counterB = new Counter(); + Thread threadA = new CounterThread(counterA); + Thread threadB = new CounterThread(counterB); + + threadA.start(); + threadB.start(); + } + } +``` + +Notice how the two threads, threadA and threadB, no longer reference the same counter instance. The add method of counterA and counterB are synchronized on their two owning instances. Calling add() on counterA will thus not block a call to add() on counterB. + +##Java Concurrency Utilities + +The synchronized mechanism was Java's first mechanism for synchronizing access to objects shared by multiple threads. The synchronized mechanism isn't very advanced though. That is why Java 5 got a whole set of concurrency utility classes to help developers implement more fine grained concurrency control than what you get with synchronized. \ No newline at end of file From 5059947266b9d2ce1d173d17d49dbcd81c9fabd5 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 10:14:52 +0800 Subject: [PATCH 136/524] Published with https://stackedit.io/ --- .../08.Java\345\220\214\346\255\245\345\235\227" | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" index 40668d6..b96e826 100644 --- "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" @@ -20,7 +20,7 @@ Java中的同步块使用关键字**synchronized**进行标记**。同步块在J ##同步实例方法(Synchronized Instance Methods) -Here is a synchronized instance method: +下面是一个同步的实例方法: ```Java public synchronized void add(int value){ @@ -28,7 +28,9 @@ Here is a synchronized instance method: } ``` -Notice the use of the synchronized keyword in the method declaration. This tells Java that the method is synchronized. +使用**synchronized**关键字对方法进行声明,告诉JVM这是一个同步的方法。 + + A synchronized instance method in Java is synchronized on the instance (object) owning the method. Thus, each instance has its synchronized methods synchronized on a different object: the owning instance. Only one thread can execute inside a synchronized instance method. If more than one instance exist, then one thread at a time can execute inside a synchronized instance method per instance. One thread per instance. From 8954d32d369e53c818d5216f5962438113886a2a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 10:34:42 +0800 Subject: [PATCH 137/524] Published with https://stackedit.io/ --- .../08.Java\345\220\214\346\255\245\345\235\227" | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" index b96e826..5ac7f75 100644 --- "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" @@ -30,9 +30,7 @@ Java中的同步块使用关键字**synchronized**进行标记**。同步块在J 使用**synchronized**关键字对方法进行声明,告诉JVM这是一个同步的方法。 - - -A synchronized instance method in Java is synchronized on the instance (object) owning the method. Thus, each instance has its synchronized methods synchronized on a different object: the owning instance. Only one thread can execute inside a synchronized instance method. If more than one instance exist, then one thread at a time can execute inside a synchronized instance method per instance. One thread per instance. +Java中的同步实例方法是基于这个方法所属的实例对象上进行同步的。因此,每一个同步实例方法都是基于各自的实例对象进行同步的。同一时间,只有一个线程可以访问一个实例对象的同步实例方法。如果有多个实例存在,那么每个线程都可以同时访问各自不同实例对象的同步实例方法,一个实例对象对应一个线程。 ##同步静态方法(Synchronized Static Methods) From 44abb99d3b62b93869db27ce7c769043fcf13d11 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 11:11:54 +0800 Subject: [PATCH 138/524] Published with https://stackedit.io/ --- ....Java\345\220\214\346\255\245\345\235\227" | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" index 5ac7f75..ae64565 100644 --- "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" @@ -30,11 +30,11 @@ Java中的同步块使用关键字**synchronized**进行标记**。同步块在J 使用**synchronized**关键字对方法进行声明,告诉JVM这是一个同步的方法。 -Java中的同步实例方法是基于这个方法所属的实例对象上进行同步的。因此,每一个同步实例方法都是基于各自的实例对象进行同步的。同一时间,只有一个线程可以访问一个实例对象的同步实例方法。如果有多个实例存在,那么每个线程都可以同时访问各自不同实例对象的同步实例方法,一个实例对象对应一个线程。 +Java中的**同步实例方法是基于这个方法所属的实例对象上进行同步的**。因此,每一个同步实例方法都是基于各自的实例对象进行同步的。同一时间,只有一个线程可以访问一个实例对象的同步实例方法。如果有多个实例存在,那么每个线程都可以同时访问各自不同实例对象的同步实例方法,一个实例对象对应一个线程。 ##同步静态方法(Synchronized Static Methods) -Static methods are marked as synchronized just like instance methods using the synchronized keyword. Here is a Java synchronized static method example: +静态方法的同步与实例方法一致,都是使用**synchronized**在方法放进行声明。 ```Java public static synchronized void add(int value){ @@ -42,17 +42,17 @@ Static methods are marked as synchronized just like instance methods using the s } ``` -Also here the synchronized keyword tells Java that the method is synchronized. +同样的,这里的**synchronized**关键字用于告诉JVM这个静态方法是同步的。 -Synchronized static methods are synchronized on the class object of the class the synchronized static method belongs to. Since only one class object exists in the Java VM per class, only one thread can execute inside a static synchronized method in the same class. +**同步静态方法是基于这个静态方法所属的类对象进行同步的**。由于在JVM中,每个类有且只有一个类对象,因此,在同一时间内,只有一个线程能够访问同一个类的同步静态方法。 -If the static synchronized methods are located in different classes, then one thread can execute inside the static synchronized methods of each class. One thread per class regardless of which static synchronized method it calls. +如果同步静态方法位于不同的类中,那么每个线程都可以访问各自对应的类的同步静态方法,一个线程对应一个类。 ##实例方法中的同步块(Synchronized Blocks in Instance Methods) -You do not have to synchronize a whole method. Sometimes it is preferable to synchronize only part of a method. Java synchronized blocks inside methods makes this possible. +有些时候,你并不需要同步整一个方法,而只需要同步这个方法下的一小部分代码块。你可以在方法里面使用同步代码块。 -Here is a synchronized block of Java code inside an unsynchronized Java method: +下面这个例子就是在非同步方法里面使用了同步代码块: ```Java public void add(int value){ @@ -63,11 +63,11 @@ Here is a synchronized block of Java code inside an unsynchronized Java method: } ``` -This example uses the Java synchronized block construct to mark a block of code as synchronized. This code will now execute as if it was a synchronized method. +这个例子里,用了Java的同步代码块来使代码进行同步,让这个方法像同步方法一样执行。 -Notice how the Java synchronized block construct takes an object in parentheses. In the example "this" is used, which is the instance the add method is called on. The object taken in the parentheses by the synchronized construct is called a monitor object. The code is said to be synchronized on the monitor object. A synchronized instance method uses the object it belongs to as monitor object. +注意在Java的同步代码块里,需要在括号里传递一个对象。这个例子中,这个对象是**this**,this指的是这个实例对象本身。在Java同步代码块括号中的对象称为**监听器对象**。意味着,这个同步块是基于这个监听器对象进行同步的。同步实例方法使用其所在实例对象作为监听器对象。 -Only one thread can execute inside a Java code block synchronized on the same monitor object. +**同一时间,只有一个线程能够访问基于同一个监听器对象的同步代码块。** The following two examples are both synchronized on the instance they are called on. They are therefore equivalent with respect to synchronization: From 60a25560c8b2d5e362a31e1f11cdb73ebc2dd338 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 11:35:48 +0800 Subject: [PATCH 139/524] Published with https://stackedit.io/ --- .../08.Java\345\220\214\346\255\245\345\235\227" | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" index ae64565..55fd149 100644 --- "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" @@ -67,9 +67,9 @@ Java中的**同步实例方法是基于这个方法所属的实例对象上进 注意在Java的同步代码块里,需要在括号里传递一个对象。这个例子中,这个对象是**this**,this指的是这个实例对象本身。在Java同步代码块括号中的对象称为**监听器对象**。意味着,这个同步块是基于这个监听器对象进行同步的。同步实例方法使用其所在实例对象作为监听器对象。 -**同一时间,只有一个线程能够访问基于同一个监听器对象的同步代码块。** +**同一时间,只有一个线程能够访问基于同一个监听器对象的同步代码。** -The following two examples are both synchronized on the instance they are called on. They are therefore equivalent with respect to synchronization: +下面这个例子,两个同步代码都是基于同一个实例对象进行同步的: ```Java public class MyClass { @@ -89,13 +89,13 @@ The following two examples are both synchronized on the instance they are called } ``` -Thus only a single thread can execute inside either of the two synchronized blocks in this example. +因此,在这个例子中,每次仅能有一个线程能够访问这两个同步代码的任意一个同步代码。 -Had the second synchronized block been synchronized on a different object than this, then one thread at a time had been able to execute inside each method. +如果第二个同步块是基于其他监听器对象,例如`synchronized (this.getClass()) {}`,则此时第一个和第二个同步代码的监听器对象分别为:当前实例对象和当前类对象。因此,这两个同步代码可以同时由不同的线程进行访问。 ##静态方法中的同步块(Synchronized Blocks in Static Methods) -Here are the same two examples as static methods. These methods are synchronized on the class object of the class the methods belong to: +下面这个例子中,两个同步代码都是基于当前的类对象进行同步的: ```Java public class MyClass { @@ -115,9 +115,10 @@ Here are the same two examples as static methods. These methods are synchronized } ``` -Only one thread can execute inside any of these two methods at the same time. +同一时间,只有一个线程能够访问这两个同步代码的任意一个同步代码。 + +如果第二个方法的监听器对象非MyClass.class对象,则两个同步代码可以同时被两个线程访问。 -Had the second synchronized block been synchronized on a different object than MyClass.class, then one thread could execute inside each method at the same time. ##Java同步示例(Java Synchronized Example) From 1e2f71a6abe318d8191f15a915e55570cdabc96f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 14:03:20 +0800 Subject: [PATCH 140/524] Published with https://stackedit.io/ --- ....Java\345\220\214\346\255\245\345\235\227" | 86 +++++++++---------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" index 55fd149..9edb617 100644 --- "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" +++ "b/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" @@ -125,39 +125,37 @@ Java中的**同步实例方法是基于这个方法所属的实例对象上进 Here is an example that starts 2 threads and have both of them call the add method on the same instance of Counter. Only one thread at a time will be able to call the add method on the same instance, because the method is synchronized on the instance it belongs to. ```Java - public class Counter{ - - long count = 0; - - public synchronized void add(long value){ - this.count += value; - } - } - public class CounterThread extends Thread{ - - protected Counter counter = null; - - public CounterThread(Counter counter){ - this.counter = counter; - } - - public void run() { - for(int i=0; i<10; i++){ - counter.add(i); - } - } - } - public class Example { - - public static void main(String[] args){ - Counter counter = new Counter(); - Thread threadA = new CounterThread(counter); - Thread threadB = new CounterThread(counter); - - threadA.start(); - threadB.start(); - } +public class Counter{ + long count = 0; + + public synchronized void add(long value){ + this.count += value; + } +} +public class CounterThread extends Thread{ + protected Counter counter = null; + + public CounterThread(Counter counter){ + this.counter = counter; + } + + public void run() { +for(int i=0; i<10; i++){ + counter.add(i); + } + } +} +public class Example { + + public static void main(String[] args){ + Counter counter = new Counter(); + Thread threadA = new CounterThread(counter); + Thread threadB = new CounterThread(counter); + + threadA.start(); + threadB.start(); } +} ``` Two threads are created. The same Counter instance is passed to both of them in their constructor. The Counter.add() method is synchronized on the instance, because the add method is an instance method, and marked as synchronized. Therefore only one of the threads can call the add() method at a time. The other thread will wait until the first thread leaves the add() method, before it can execute the method itself. @@ -165,22 +163,22 @@ Two threads are created. The same Counter instance is passed to both of them in If the two threads had referenced two separate Counter instances, there would have been no problems calling the add() methods simultaneously. The calls would have been to different objects, so the methods called would also be synchronized on different objects (the object owning the method). Therefore the calls would not block. Here is how that could look: ```Java - public class Example { - - public static void main(String[] args){ - Counter counterA = new Counter(); - Counter counterB = new Counter(); - Thread threadA = new CounterThread(counterA); - Thread threadB = new CounterThread(counterB); - - threadA.start(); - threadB.start(); - } +public class Example { + public static void main(String[] args){ + Counter counterA = new Counter(); + Counter counterB = new Counter(); + Thread threadA = new CounterThread(counterA); + Thread threadB = new CounterThread(counterB); + + threadA.start(); + threadB.start(); } +} ``` Notice how the two threads, threadA and threadB, no longer reference the same counter instance. The add method of counterA and counterB are synchronized on their two owning instances. Calling add() on counterA will thus not block a call to add() on counterB. ##Java Concurrency Utilities -The synchronized mechanism was Java's first mechanism for synchronizing access to objects shared by multiple threads. The synchronized mechanism isn't very advanced though. That is why Java 5 got a whole set of concurrency utility classes to help developers implement more fine grained concurrency control than what you get with synchronized. \ No newline at end of file +`synchronized`机制是Java第一个引进的用于同步多线程资源共享的机制。然而`synchroniez`机制并不高效。这就是为什么Java 5提供了一整套的并发工具类,以帮助开发人员实现更细粒度的并发控制 +。 \ No newline at end of file From 2dd033021d74dd2d92c1c4472626302d223b9ed6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 14:08:05 +0800 Subject: [PATCH 141/524] Published with https://stackedit.io/ --- ...77\347\250\213\351\200\232\344\277\241.md" | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 "Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" new file mode 100644 index 0000000..f81ed30 --- /dev/null +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -0,0 +1,189 @@ +#09.线程通讯 + +The purpose of thread signaling is to enable threads to send signals to each other. Additionally, thread signaling enables threads to wait for signals from other threads. For instance, a thread B might wait for a signal from thread A indicating that data is ready to be processed. + +Signaling via Shared Objects + +A simple way for threads to send signals to each other is by setting the signal values in some shared object variable. Thread A may set the boolean member variable hasDataToProcess to true from inside a synchronized block, and thread B may read the hasDataToProcess member variable, also inside a synchronized block. Here is a simple example of an object that can hold such a signal, and provide methods to set and check it: + +public class MySignal{ + + protected boolean hasDataToProcess = false; + + public synchronized boolean hasDataToProcess(){ + return this.hasDataToProcess; + } + + public synchronized void setHasDataToProcess(boolean hasData){ + this.hasDataToProcess = hasData; + } + +} +Thread A and B must have a reference to a shared MySignal instance for the signaling to work. If thread A and B has references to different MySignal instance, they will not detect each others signals. The data to be processed can be located in a shared buffer separate from the MySignal instance. + +Busy Wait + +Thread B which is to process the data is waiting for data to become available for processing. In other words, it is waiting for a signal from thread A which causes hasDataToProcess() to return true. Here is the loop that thread B is running in, while waiting for this signal: + +protected MySignal sharedSignal = ... + +... + +while(!sharedSignal.hasDataToProcess()){ + //do nothing... busy waiting +} +Notice how the while loop keeps executing until hasDataToProcess() returns true. This is called busy waiting. The thread is busy while waiting. + +wait(), notify() and notifyAll() + +Busy waiting is not a very efficient utilization of the CPU in the computer running the waiting thread, except if the average waiting time is very small. Else, it would be smarter if the waiting thread could somehow sleep or become inactive until it receives the signal it is waiting for. + +Java has a builtin wait mechanism that enable threads to become inactive while waiting for signals. The class java.lang.Object defines three methods, wait(), notify(), and notifyAll(), to facilitate this. + +A thread that calls wait() on any object becomes inactive until another thread calls notify() on that object. In order to call either wait() or notify the calling thread must first obtain the lock on that object. In other words, the calling thread must call wait() or notify() from inside a synchronized block. Here is a modified version of MySignal called MyWaitNotify that uses wait() and notify(). + + +public class MonitorObject{ +} + +public class MyWaitNotify{ + + MonitorObject myMonitorObject = new MonitorObject(); + + public void doWait(){ + synchronized(myMonitorObject){ + try{ + myMonitorObject.wait(); + } catch(InterruptedException e){...} + } + } + + public void doNotify(){ + synchronized(myMonitorObject){ + myMonitorObject.notify(); + } + } +} +The waiting thread would call doWait(), and the notifying thread would call doNotify(). When a thread calls notify() on an object, one of the threads waiting on that object are awakened and allowed to execute. There is also a notifyAll() method that will wake all threads waiting on a given object. + +As you can see both the waiting and notifying thread calls wait() and notify() from within a synchronized block. This is mandatory! A thread cannot call wait(), notify() or notifyAll() without holding the lock on the object the method is called on. If it does, an IllegalMonitorStateException is thrown. + +But, how is this possible? Wouldn't the waiting thread keep the lock on the monitor object (myMonitorObject) as long as it is executing inside a synchronized block? Will the waiting thread not block the notifying thread from ever entering the synchronized block in doNotify()? The answer is no. Once a thread calls wait() it releases the lock it holds on the monitor object. This allows other threads to call wait() or notify() too, since these methods must be called from inside a synchronized block. + +Once a thread is awakened it cannot exit the wait() call until the thread calling notify() has left its synchronized block. In other words: The awakened thread must reobtain the lock on the monitor object before it can exit the wait() call, because the wait call is nested inside a synchronized block. If multiple threads are awakened using notifyAll() only one awakened thread at a time can exit the wait() method, since each thread must obtain the lock on the monitor object in turn before exiting wait(). + +Missed Signals + +The methods notify() and notifyAll() do not save the method calls to them in case no threads are waiting when they are called. The notify signal is then just lost. Therefore, if a thread calls notify() before the thread to signal has called wait(), the signal will be missed by the waiting thread. This may or may not be a problem, but in some cases this may result in the waiting thread waiting forever, never waking up, because the signal to wake up was missed. + +To avoid losing signals they should be stored inside the signal class. In the MyWaitNotify example the notify signal should be stored in a member variable inside the MyWaitNotify instance. Here is a modified version of MyWaitNotify that does this: + +public class MyWaitNotify2{ + + MonitorObject myMonitorObject = new MonitorObject(); + boolean wasSignalled = false; + + public void doWait(){ + synchronized(myMonitorObject){ + if(!wasSignalled){ + try{ + myMonitorObject.wait(); + } catch(InterruptedException e){...} + } + //clear signal and continue running. + wasSignalled = false; + } + } + + public void doNotify(){ + synchronized(myMonitorObject){ + wasSignalled = true; + myMonitorObject.notify(); + } + } +} +Notice how the doNotify() method now sets the wasSignalled variable to true before calling notify(). Also, notice how the doWait() method now checks the wasSignalled variable before calling wait(). In fact it only calls wait() if no signal was received in between the previous doWait() call and this. + +Spurious Wakeups + +For inexplicable reasons it is possible for threads to wake up even if notify() and notifyAll() has not been called. This is known as spurious wakeups. Wakeups without any reason. + +If a spurious wakeup occurs in the MyWaitNofity2 class's doWait() method the waiting thread may continue processing without having received a proper signal to do so! This could cause serious problems in your application. + +To guard against spurious wakeups the signal member variable is checked inside a while loop instead of inside an if-statement. Such a while loop is also called a spin lock. The thread awakened spins around until the condition in the spin lock (while loop) becomes false. Here is a modified version of MyWaitNotify2 that shows this: + +public class MyWaitNotify3{ + + MonitorObject myMonitorObject = new MonitorObject(); + boolean wasSignalled = false; + + public void doWait(){ + synchronized(myMonitorObject){ + while(!wasSignalled){ + try{ + myMonitorObject.wait(); + } catch(InterruptedException e){...} + } + //clear signal and continue running. + wasSignalled = false; + } + } + + public void doNotify(){ + synchronized(myMonitorObject){ + wasSignalled = true; + myMonitorObject.notify(); + } + } +} +Notice how the wait() call is now nested inside a while loop instead of an if-statement. If the waiting thread wakes up without having received a signal, the wasSignalled member will still be false, and the while loop will execute once more, causing the awakened thread to go back to waiting. + +Multiple Threads Waiting for the Same Signals + +The while loop is also a nice solution if you have multiple threads waiting, which are all awakened using notifyAll(), but only one of them should be allowed to continue. Only one thread at a time will be able to obtain the lock on the monitor object, meaning only one thread can exit the wait() call and clear the wasSignalled flag. Once this thread then exits the synchronized block in the doWait() method, the other threads can exit the wait() call and check the wasSignalled member variable inside the while loop. However, this flag was cleared by the first thread waking up, so the rest of the awakened threads go back to waiting, until the next signal arrives. + + +Don't call wait() on constant String's or global objects + +An earlier version of this text had an edition of the MyWaitNotify example class which used a constant string ( "" ) as monitor object. Here is how that example looked: + +public class MyWaitNotify{ + + String myMonitorObject = ""; + boolean wasSignalled = false; + + public void doWait(){ + synchronized(myMonitorObject){ + while(!wasSignalled){ + try{ + myMonitorObject.wait(); + } catch(InterruptedException e){...} + } + //clear signal and continue running. + wasSignalled = false; + } + } + + public void doNotify(){ + synchronized(myMonitorObject){ + wasSignalled = true; + myMonitorObject.notify(); + } + } +} +The problem with calling wait() and notify() on the empty string, or any other constant string is, that the JVM/Compiler internally translates constant strings into the same object. That means, that even if you have two different MyWaitNotify instances, they both reference the same empty string instance. This also means that threads calling doWait() on the first MyWaitNotify instance risk being awakened by doNotify() calls on the second MyWaitNotify instance. + +The situation is sketched in the diagram below: + +Calling wait()/notify() on string constants +Remember, that even if the 4 threads call wait() and notify() on the same shared string instance, the signals from the doWait() and doNotify() calls are stored individually in the two MyWaitNotify instances. A doNotify() call on the MyWaitNotify 1 may wake threads waiting in MyWaitNotify 2, but the signal will only be stored in MyWaitNotify 1. + +At first this may not seem like a big problem. After all, if doNotify() is called on the second MyWaitNotify instance all that can really happen is that Thread A and B are awakened by mistake. This awakened thread (A or B) will check its signal in the while loop, and go back to waiting because doNotify() was not called on the first MyWaitNotify instance, in which they are waiting. This situation is equal to a provoked spurious wakeup. Thread A or B awakens without having been signaled. But the code can handle this, so the threads go back to waiting. + +The problem is, that since the doNotify() call only calls notify() and not notifyAll(), only one thread is awakened even if 4 threads are waiting on the same string instance (the empty string). So, if one of the threads A or B is awakened when really the signal was for C or D, the awakened thread (A or B) will check its signal, see that no signal was received, and go back to waiting. Neither C or D wakes up to check the signal they had actually received, so the signal is missed. This situation is equal to the missed signals problem described earlier. C and D were sent a signal but fail to respond to it. + +If the doNotify() method had called notifyAll() instead of notify(), all waiting threads had been awakened and checked for signals in turn. Thread A and B would have gone back to waiting, but one of either C or D would have noticed the signal and left the doWait() method call. The other of C and D would go back to waiting, because the thread discovering the signal clears it on the way out of doWait(). + +You may be tempted then to always call notifyAll() instead notify(), but this is a bad idea performance wise. There is no reason to wake up all threads waiting when only one of them can respond to the signal. + +So: Don't use global objects, string constants etc. for wait() / notify() mechanisms. Use an object that is unique to the construct using it. For instance, each MyWaitNotify3 (example from earlier sections) instance has its own MonitorObject instance rather than using the empty string for wait() / notify() calls. \ No newline at end of file From 2b8797e957f29b99b61cc455e1413872ce21c73f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 14:09:29 +0800 Subject: [PATCH 142/524] Published with https://stackedit.io/ --- ...272\277\347\250\213\351\200\232\344\277\241.md" | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index f81ed30..a9695c9 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -1,8 +1,8 @@ -#09.线程通讯 +#09.线程通信 The purpose of thread signaling is to enable threads to send signals to each other. Additionally, thread signaling enables threads to wait for signals from other threads. For instance, a thread B might wait for a signal from thread A indicating that data is ready to be processed. -Signaling via Shared Objects +##Signaling via Shared Objects A simple way for threads to send signals to each other is by setting the signal values in some shared object variable. Thread A may set the boolean member variable hasDataToProcess to true from inside a synchronized block, and thread B may read the hasDataToProcess member variable, also inside a synchronized block. Here is a simple example of an object that can hold such a signal, and provide methods to set and check it: @@ -21,7 +21,7 @@ public class MySignal{ } Thread A and B must have a reference to a shared MySignal instance for the signaling to work. If thread A and B has references to different MySignal instance, they will not detect each others signals. The data to be processed can be located in a shared buffer separate from the MySignal instance. -Busy Wait +##Busy Wait Thread B which is to process the data is waiting for data to become available for processing. In other words, it is waiting for a signal from thread A which causes hasDataToProcess() to return true. Here is the loop that thread B is running in, while waiting for this signal: @@ -72,7 +72,7 @@ But, how is this possible? Wouldn't the waiting thread keep the lock on the moni Once a thread is awakened it cannot exit the wait() call until the thread calling notify() has left its synchronized block. In other words: The awakened thread must reobtain the lock on the monitor object before it can exit the wait() call, because the wait call is nested inside a synchronized block. If multiple threads are awakened using notifyAll() only one awakened thread at a time can exit the wait() method, since each thread must obtain the lock on the monitor object in turn before exiting wait(). -Missed Signals +##Missed Signals The methods notify() and notifyAll() do not save the method calls to them in case no threads are waiting when they are called. The notify signal is then just lost. Therefore, if a thread calls notify() before the thread to signal has called wait(), the signal will be missed by the waiting thread. This may or may not be a problem, but in some cases this may result in the waiting thread waiting forever, never waking up, because the signal to wake up was missed. @@ -104,7 +104,7 @@ public class MyWaitNotify2{ } Notice how the doNotify() method now sets the wasSignalled variable to true before calling notify(). Also, notice how the doWait() method now checks the wasSignalled variable before calling wait(). In fact it only calls wait() if no signal was received in between the previous doWait() call and this. -Spurious Wakeups +##Spurious Wakeups For inexplicable reasons it is possible for threads to wake up even if notify() and notifyAll() has not been called. This is known as spurious wakeups. Wakeups without any reason. @@ -143,7 +143,7 @@ Multiple Threads Waiting for the Same Signals The while loop is also a nice solution if you have multiple threads waiting, which are all awakened using notifyAll(), but only one of them should be allowed to continue. Only one thread at a time will be able to obtain the lock on the monitor object, meaning only one thread can exit the wait() call and clear the wasSignalled flag. Once this thread then exits the synchronized block in the doWait() method, the other threads can exit the wait() call and check the wasSignalled member variable inside the while loop. However, this flag was cleared by the first thread waking up, so the rest of the awakened threads go back to waiting, until the next signal arrives. -Don't call wait() on constant String's or global objects +##Don't call wait() on constant String's or global objects An earlier version of this text had an edition of the MyWaitNotify example class which used a constant string ( "" ) as monitor object. Here is how that example looked: @@ -173,7 +173,7 @@ public class MyWaitNotify{ } The problem with calling wait() and notify() on the empty string, or any other constant string is, that the JVM/Compiler internally translates constant strings into the same object. That means, that even if you have two different MyWaitNotify instances, they both reference the same empty string instance. This also means that threads calling doWait() on the first MyWaitNotify instance risk being awakened by doNotify() calls on the second MyWaitNotify instance. -The situation is sketched in the diagram below: +##The situation is sketched in the diagram below: Calling wait()/notify() on string constants Remember, that even if the 4 threads call wait() and notify() on the same shared string instance, the signals from the doWait() and doNotify() calls are stored individually in the two MyWaitNotify instances. A doNotify() call on the MyWaitNotify 1 may wake threads waiting in MyWaitNotify 2, but the signal will only be stored in MyWaitNotify 1. From 22e23673fbe0182318e61faa797aedb8467333e0 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 14:14:59 +0800 Subject: [PATCH 143/524] Published with https://stackedit.io/ --- .../09.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index a9695c9..61e6747 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -173,7 +173,9 @@ public class MyWaitNotify{ } The problem with calling wait() and notify() on the empty string, or any other constant string is, that the JVM/Compiler internally translates constant strings into the same object. That means, that even if you have two different MyWaitNotify instances, they both reference the same empty string instance. This also means that threads calling doWait() on the first MyWaitNotify instance risk being awakened by doNotify() calls on the second MyWaitNotify instance. -##The situation is sketched in the diagram below: +The situation is sketched in the diagram below: + + Calling wait()/notify() on string constants Remember, that even if the 4 threads call wait() and notify() on the same shared string instance, the signals from the doWait() and doNotify() calls are stored individually in the two MyWaitNotify instances. A doNotify() call on the MyWaitNotify 1 may wake threads waiting in MyWaitNotify 2, but the signal will only be stored in MyWaitNotify 1. From fa0c19000f8945b85c3c51142c795fc562147f2d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 14:25:29 +0800 Subject: [PATCH 144/524] Published with https://stackedit.io/ --- ...9.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index 61e6747..246b466 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -1,8 +1,8 @@ #09.线程通信 -The purpose of thread signaling is to enable threads to send signals to each other. Additionally, thread signaling enables threads to wait for signals from other threads. For instance, a thread B might wait for a signal from thread A indicating that data is ready to be processed. +线程通信的目的在于:让线程之间可以彼此发送信号。因此,线程通信也让线程等待其他线程发送的信号。举个例子,线程B等待线程A的信号,这个信号用于通知线程B数据已经准备就绪。 -##Signaling via Shared Objects +##通过共享对象通信(Signaling via Shared Objects) A simple way for threads to send signals to each other is by setting the signal values in some shared object variable. Thread A may set the boolean member variable hasDataToProcess to true from inside a synchronized block, and thread B may read the hasDataToProcess member variable, also inside a synchronized block. Here is a simple example of an object that can hold such a signal, and provide methods to set and check it: @@ -21,7 +21,7 @@ public class MySignal{ } Thread A and B must have a reference to a shared MySignal instance for the signaling to work. If thread A and B has references to different MySignal instance, they will not detect each others signals. The data to be processed can be located in a shared buffer separate from the MySignal instance. -##Busy Wait +##忙等待(Busy Wait) Thread B which is to process the data is waiting for data to become available for processing. In other words, it is waiting for a signal from thread A which causes hasDataToProcess() to return true. Here is the loop that thread B is running in, while waiting for this signal: @@ -34,7 +34,7 @@ while(!sharedSignal.hasDataToProcess()){ } Notice how the while loop keeps executing until hasDataToProcess() returns true. This is called busy waiting. The thread is busy while waiting. -wait(), notify() and notifyAll() +##wait(), notify() and notifyAll() Busy waiting is not a very efficient utilization of the CPU in the computer running the waiting thread, except if the average waiting time is very small. Else, it would be smarter if the waiting thread could somehow sleep or become inactive until it receives the signal it is waiting for. From 54a679d744ee4a8fe2ac43b4b49d8f69f0a7e27c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 14:27:02 +0800 Subject: [PATCH 145/524] Published with https://stackedit.io/ --- ...77\347\250\213\351\200\232\344\277\241.md" | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index 246b466..8984f6a 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -6,6 +6,7 @@ A simple way for threads to send signals to each other is by setting the signal values in some shared object variable. Thread A may set the boolean member variable hasDataToProcess to true from inside a synchronized block, and thread B may read the hasDataToProcess member variable, also inside a synchronized block. Here is a simple example of an object that can hold such a signal, and provide methods to set and check it: +```Java public class MySignal{ protected boolean hasDataToProcess = false; @@ -19,12 +20,15 @@ public class MySignal{ } } +``` + Thread A and B must have a reference to a shared MySignal instance for the signaling to work. If thread A and B has references to different MySignal instance, they will not detect each others signals. The data to be processed can be located in a shared buffer separate from the MySignal instance. ##忙等待(Busy Wait) Thread B which is to process the data is waiting for data to become available for processing. In other words, it is waiting for a signal from thread A which causes hasDataToProcess() to return true. Here is the loop that thread B is running in, while waiting for this signal: +```Java protected MySignal sharedSignal = ... ... @@ -32,6 +36,8 @@ protected MySignal sharedSignal = ... while(!sharedSignal.hasDataToProcess()){ //do nothing... busy waiting } +``` + Notice how the while loop keeps executing until hasDataToProcess() returns true. This is called busy waiting. The thread is busy while waiting. ##wait(), notify() and notifyAll() @@ -42,7 +48,7 @@ Java has a builtin wait mechanism that enable threads to become inactive while w A thread that calls wait() on any object becomes inactive until another thread calls notify() on that object. In order to call either wait() or notify the calling thread must first obtain the lock on that object. In other words, the calling thread must call wait() or notify() from inside a synchronized block. Here is a modified version of MySignal called MyWaitNotify that uses wait() and notify(). - +```Java public class MonitorObject{ } @@ -64,6 +70,8 @@ public class MyWaitNotify{ } } } +``` + The waiting thread would call doWait(), and the notifying thread would call doNotify(). When a thread calls notify() on an object, one of the threads waiting on that object are awakened and allowed to execute. There is also a notifyAll() method that will wake all threads waiting on a given object. As you can see both the waiting and notifying thread calls wait() and notify() from within a synchronized block. This is mandatory! A thread cannot call wait(), notify() or notifyAll() without holding the lock on the object the method is called on. If it does, an IllegalMonitorStateException is thrown. @@ -78,6 +86,7 @@ The methods notify() and notifyAll() do not save the method calls to them in cas To avoid losing signals they should be stored inside the signal class. In the MyWaitNotify example the notify signal should be stored in a member variable inside the MyWaitNotify instance. Here is a modified version of MyWaitNotify that does this: +```Java public class MyWaitNotify2{ MonitorObject myMonitorObject = new MonitorObject(); @@ -102,6 +111,8 @@ public class MyWaitNotify2{ } } } +``` + Notice how the doNotify() method now sets the wasSignalled variable to true before calling notify(). Also, notice how the doWait() method now checks the wasSignalled variable before calling wait(). In fact it only calls wait() if no signal was received in between the previous doWait() call and this. ##Spurious Wakeups @@ -112,6 +123,7 @@ If a spurious wakeup occurs in the MyWaitNofity2 class's doWait() method the wai To guard against spurious wakeups the signal member variable is checked inside a while loop instead of inside an if-statement. Such a while loop is also called a spin lock. The thread awakened spins around until the condition in the spin lock (while loop) becomes false. Here is a modified version of MyWaitNotify2 that shows this: +```Java public class MyWaitNotify3{ MonitorObject myMonitorObject = new MonitorObject(); @@ -136,9 +148,11 @@ public class MyWaitNotify3{ } } } +``` + Notice how the wait() call is now nested inside a while loop instead of an if-statement. If the waiting thread wakes up without having received a signal, the wasSignalled member will still be false, and the while loop will execute once more, causing the awakened thread to go back to waiting. -Multiple Threads Waiting for the Same Signals +##Multiple Threads Waiting for the Same Signals The while loop is also a nice solution if you have multiple threads waiting, which are all awakened using notifyAll(), but only one of them should be allowed to continue. Only one thread at a time will be able to obtain the lock on the monitor object, meaning only one thread can exit the wait() call and clear the wasSignalled flag. Once this thread then exits the synchronized block in the doWait() method, the other threads can exit the wait() call and check the wasSignalled member variable inside the while loop. However, this flag was cleared by the first thread waking up, so the rest of the awakened threads go back to waiting, until the next signal arrives. @@ -147,6 +161,7 @@ The while loop is also a nice solution if you have multiple threads waiting, whi An earlier version of this text had an edition of the MyWaitNotify example class which used a constant string ( "" ) as monitor object. Here is how that example looked: +```Java public class MyWaitNotify{ String myMonitorObject = ""; @@ -171,6 +186,8 @@ public class MyWaitNotify{ } } } +``` + The problem with calling wait() and notify() on the empty string, or any other constant string is, that the JVM/Compiler internally translates constant strings into the same object. That means, that even if you have two different MyWaitNotify instances, they both reference the same empty string instance. This also means that threads calling doWait() on the first MyWaitNotify instance risk being awakened by doNotify() calls on the second MyWaitNotify instance. The situation is sketched in the diagram below: From 5219b2ab21d3cca5fd0d9e2c58f06facb06812c7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 14:29:07 +0800 Subject: [PATCH 146/524] Published with https://stackedit.io/ --- .../10.\346\255\273\351\224\201.md" | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 "Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" diff --git "a/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" "b/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" new file mode 100644 index 0000000..3d73037 --- /dev/null +++ "b/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" @@ -0,0 +1,80 @@ +#10.死锁 + +A deadlock is when two or more threads are blocked waiting to obtain locks that some of the other threads in the deadlock are holding. Deadlock can occur when multiple threads need the same locks, at the same time, but obtain them in different order. + +For instance, if thread 1 locks A, and tries to lock B, and thread 2 has already locked B, and tries to lock A, a deadlock arises. Thread 1 can never get B, and thread 2 can never get A. In addition, neither of them will ever know. They will remain blocked on each their object, A and B, forever. This situation is a deadlock. + +The situation is illustrated below: + +Thread 1 locks A, waits for B +Thread 2 locks B, waits for A +Here is an example of a TreeNode class that call synchronized methods in different instances: + +public class TreeNode { + + TreeNode parent = null; + List children = new ArrayList(); + + public synchronized void addChild(TreeNode child){ + if(!this.children.contains(child)) { + this.children.add(child); + child.setParentOnly(this); + } + } + + public synchronized void addChildOnly(TreeNode child){ + if(!this.children.contains(child){ + this.children.add(child); + } + } + + public synchronized void setParent(TreeNode parent){ + this.parent = parent; + parent.addChildOnly(this); + } + + public synchronized void setParentOnly(TreeNode parent){ + this.parent = parent; + } +} +If a thread (1) calls the parent.addChild(child) method at the same time as another thread (2) calls the child.setParent(parent) method, on the same parent and child instances, a deadlock can occur. Here is some pseudo code that illustrates this: + +Thread 1: parent.addChild(child); //locks parent + --> child.setParentOnly(parent); + +Thread 2: child.setParent(parent); //locks child + --> parent.addChildOnly() +First thread 1 calls parent.addChild(child). Since addChild() is synchronized thread 1 effectively locks the parent object for access from other treads. + +Then thread 2 calls child.setParent(parent). Since setParent() is synchronized thread 2 effectively locks the child object for acces from other threads. + +Now both child and parent objects are locked by two different threads. Next thread 1 tries to call child.setParentOnly() method, but the child object is locked by thread 2, so the method call just blocks. Thread 2 also tries to call parent.addChildOnly() but the parent object is locked by thread 1, causing thread 2 to block on that method call. Now both threads are blocked waiting to obtain locks the other thread holds. + +Note: The two threads must call parent.addChild(child) and child.setParent(parent) at the same time as described above, and on the same two parent and child instances for a deadlock to occur. The code above may execute fine for a long time until all of a sudden it deadlocks. + +The threads really need to take the locks *at the same time*. For instance, if thread 1 is a bit ahead of thread2, and thus locks both A and B, then thread 2 will be blocked already when trying to lock B. Then no deadlock occurs. Since thread scheduling often is unpredictable there is no way to predict *when* a deadlock occurs. Only that it *can* occur. + + +More Complicated Deadlocks + +Deadlock can also include more than two threads. This makes it harder to detect. Here is an example in which four threads have deadlocked: + +Thread 1 locks A, waits for B +Thread 2 locks B, waits for C +Thread 3 locks C, waits for D +Thread 4 locks D, waits for A +Thread 1 waits for thread 2, thread 2 waits for thread 3, thread 3 waits for thread 4, and thread 4 waits for thread 1. + +Database Deadlocks + +A more complicated situation in which deadlocks can occur, is a database transaction. A database transaction may consist of many SQL update requests. When a record is updated during a transaction, that record is locked for updates from other transactions, until the first transaction completes. Each update request within the same transaction may therefore lock some records in the database. + +If multiple transactions are running at the same time that need to update the same records, there is a risk of them ending up in a deadlock. + +For example + +Transaction 1, request 1, locks record 1 for update +Transaction 2, request 1, locks record 2 for update +Transaction 1, request 2, tries to lock record 2 for update. +Transaction 2, request 2, tries to lock record 1 for update. +Since the locks are taken in different requests, and not all locks needed for a given transaction are known ahead of time, it is hard to detect or prevent deadlocks in database transactions. \ No newline at end of file From 7eedddae2c51093841f0f33325141a292f7c3a6c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 14:38:06 +0800 Subject: [PATCH 147/524] Published with https://stackedit.io/ --- .../10.\346\255\273\351\224\201.md" | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" "b/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" index 3d73037..080a210 100644 --- "a/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" @@ -55,7 +55,7 @@ Note: The two threads must call parent.addChild(child) and child.setParent(paren The threads really need to take the locks *at the same time*. For instance, if thread 1 is a bit ahead of thread2, and thus locks both A and B, then thread 2 will be blocked already when trying to lock B. Then no deadlock occurs. Since thread scheduling often is unpredictable there is no way to predict *when* a deadlock occurs. Only that it *can* occur. -More Complicated Deadlocks +##More Complicated Deadlocks Deadlock can also include more than two threads. This makes it harder to detect. Here is an example in which four threads have deadlocked: @@ -65,7 +65,7 @@ Thread 3 locks C, waits for D Thread 4 locks D, waits for A Thread 1 waits for thread 2, thread 2 waits for thread 3, thread 3 waits for thread 4, and thread 4 waits for thread 1. -Database Deadlocks +##Database Deadlocks A more complicated situation in which deadlocks can occur, is a database transaction. A database transaction may consist of many SQL update requests. When a record is updated during a transaction, that record is locked for updates from other transactions, until the first transaction completes. Each update request within the same transaction may therefore lock some records in the database. @@ -73,8 +73,11 @@ If multiple transactions are running at the same time that need to update the sa For example +``` Transaction 1, request 1, locks record 1 for update Transaction 2, request 1, locks record 2 for update Transaction 1, request 2, tries to lock record 2 for update. Transaction 2, request 2, tries to lock record 1 for update. +``` + Since the locks are taken in different requests, and not all locks needed for a given transaction are known ahead of time, it is hard to detect or prevent deadlocks in database transactions. \ No newline at end of file From 45dec4b31f1494d44a1571ab820f2f768e0b32ec Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 14:41:59 +0800 Subject: [PATCH 148/524] Published with https://stackedit.io/ --- .../10.\346\255\273\351\224\201.md" | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" "b/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" index 080a210..b28a67e 100644 --- "a/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" @@ -5,11 +5,13 @@ A deadlock is when two or more threads are blocked waiting to obtain locks that For instance, if thread 1 locks A, and tries to lock B, and thread 2 has already locked B, and tries to lock A, a deadlock arises. Thread 1 can never get B, and thread 2 can never get A. In addition, neither of them will ever know. They will remain blocked on each their object, A and B, forever. This situation is a deadlock. The situation is illustrated below: - +``` Thread 1 locks A, waits for B Thread 2 locks B, waits for A +``` Here is an example of a TreeNode class that call synchronized methods in different instances: +```Java public class TreeNode { TreeNode parent = null; @@ -37,13 +39,18 @@ public class TreeNode { this.parent = parent; } } +``` + If a thread (1) calls the parent.addChild(child) method at the same time as another thread (2) calls the child.setParent(parent) method, on the same parent and child instances, a deadlock can occur. Here is some pseudo code that illustrates this: +``` Thread 1: parent.addChild(child); //locks parent --> child.setParentOnly(parent); Thread 2: child.setParent(parent); //locks child --> parent.addChildOnly() +``` + First thread 1 calls parent.addChild(child). Since addChild() is synchronized thread 1 effectively locks the parent object for access from other treads. Then thread 2 calls child.setParent(parent). Since setParent() is synchronized thread 2 effectively locks the child object for acces from other threads. @@ -58,11 +65,12 @@ The threads really need to take the locks *at the same time*. For instance, if t ##More Complicated Deadlocks Deadlock can also include more than two threads. This makes it harder to detect. Here is an example in which four threads have deadlocked: - +``` Thread 1 locks A, waits for B Thread 2 locks B, waits for C Thread 3 locks C, waits for D Thread 4 locks D, waits for A +``` Thread 1 waits for thread 2, thread 2 waits for thread 3, thread 3 waits for thread 4, and thread 4 waits for thread 1. ##Database Deadlocks From e1bb70e66f5a2cee0c93999d6c75b206ab4b85dd Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 14:42:53 +0800 Subject: [PATCH 149/524] Published with https://stackedit.io/ From 95ae6702d72b04a20bd0458eb918ae2ae2fbe614 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 16:04:25 +0800 Subject: [PATCH 150/524] Published with https://stackedit.io/ --- .../09.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index 8984f6a..e34fc97 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -8,7 +8,6 @@ A simple way for threads to send signals to each other is by setting the signal ```Java public class MySignal{ - protected boolean hasDataToProcess = false; public synchronized boolean hasDataToProcess(){ @@ -18,7 +17,6 @@ public class MySignal{ public synchronized void setHasDataToProcess(boolean hasData){ this.hasDataToProcess = hasData; } - } ``` @@ -26,13 +24,13 @@ Thread A and B must have a reference to a shared MySignal instance for the signa ##忙等待(Busy Wait) + + Thread B which is to process the data is waiting for data to become available for processing. In other words, it is waiting for a signal from thread A which causes hasDataToProcess() to return true. Here is the loop that thread B is running in, while waiting for this signal: ```Java protected MySignal sharedSignal = ... -... - while(!sharedSignal.hasDataToProcess()){ //do nothing... busy waiting } From 30f48437211fe20ba43b68294bd3d77f6870f258 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 16:32:22 +0800 Subject: [PATCH 151/524] Published with https://stackedit.io/ --- .../09.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index e34fc97..e61ddc8 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -4,7 +4,7 @@ ##通过共享对象通信(Signaling via Shared Objects) -A simple way for threads to send signals to each other is by setting the signal values in some shared object variable. Thread A may set the boolean member variable hasDataToProcess to true from inside a synchronized block, and thread B may read the hasDataToProcess member variable, also inside a synchronized block. Here is a simple example of an object that can hold such a signal, and provide methods to set and check it: +线程间进行通信,一个简单的做法就是**通过共享对象存储信号值**。线程A在同步代码块中将`hasDataToProcess`的值设为`true`,然后线程B在同步代码块中读取`hasDataToProcess`的值,这就完成了一次线程通信。下面的这个示例MySignal类用于保存信号值,并提供方法获取这个信号值: ```Java public class MySignal{ @@ -20,7 +20,7 @@ public class MySignal{ } ``` -Thread A and B must have a reference to a shared MySignal instance for the signaling to work. If thread A and B has references to different MySignal instance, they will not detect each others signals. The data to be processed can be located in a shared buffer separate from the MySignal instance. +为了进行通信,线程A和线程B必须拥有共享的MySignal的实例对象的引用。如果线程A和线程B拥有的是不同的MySignal实例引用,它们将不会检测到彼此的信号。The data to be processed can be located in a shared buffer separate from the MySignal instance. ##忙等待(Busy Wait) From bc32358fa456aae51587e3a1123a6d6ee8606ca0 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 16:47:03 +0800 Subject: [PATCH 152/524] Published with https://stackedit.io/ --- .../09.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index e61ddc8..6418ae6 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -25,8 +25,7 @@ public class MySignal{ ##忙等待(Busy Wait) - -Thread B which is to process the data is waiting for data to become available for processing. In other words, it is waiting for a signal from thread A which causes hasDataToProcess() to return true. Here is the loop that thread B is running in, while waiting for this signal: +线程B等待数据可用,然后对数据进行处理。换言之,线程B等待线程A发送的信号量,通过检测`hasDataToProcess() `的返回值,如果返回值为true,则证明此时数据准备就绪。下面的循环用于检测信号: ```Java protected MySignal sharedSignal = ... @@ -36,7 +35,8 @@ while(!sharedSignal.hasDataToProcess()){ } ``` -Notice how the while loop keeps executing until hasDataToProcess() returns true. This is called busy waiting. The thread is busy while waiting. +注意这个while循环直至`hasDataToProcess() `返回`true`才退出,这种做法称为**忙等待(Busy Waiting)**。线程在等待过程中一直处于忙碌状态。 + ##wait(), notify() and notifyAll() From a1968b8331cdc41b4d90f05e4fdf091c17af6036 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 17:11:13 +0800 Subject: [PATCH 153/524] Published with https://stackedit.io/ --- ...\272\277\347\250\213\351\200\232\344\277\241.md" | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index 6418ae6..22f9f38 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -38,14 +38,23 @@ while(!sharedSignal.hasDataToProcess()){ 注意这个while循环直至`hasDataToProcess() `返回`true`才退出,这种做法称为**忙等待(Busy Waiting)**。线程在等待过程中一直处于忙碌状态。 -##wait(), notify() and notifyAll() +##wait(), notify()和notifyAll() + +忙等待对计算机的CPU利用率并不友好,除非平均等待时间十分短暂。更好的做法是,让等待的线程处于休眠状态或非活动状态直至它收到信号。 + -Busy waiting is not a very efficient utilization of the CPU in the computer running the waiting thread, except if the average waiting time is very small. Else, it would be smarter if the waiting thread could somehow sleep or become inactive until it receives the signal it is waiting for. Java has a builtin wait mechanism that enable threads to become inactive while waiting for signals. The class java.lang.Object defines three methods, wait(), notify(), and notifyAll(), to facilitate this. A thread that calls wait() on any object becomes inactive until another thread calls notify() on that object. In order to call either wait() or notify the calling thread must first obtain the lock on that object. In other words, the calling thread must call wait() or notify() from inside a synchronized block. Here is a modified version of MySignal called MyWaitNotify that uses wait() and notify(). +忙等待是没有运行的等待线程,但如果把平均轮候时间是非常少的CPU在电脑中的一个非常有效的利用。否则,这将是更明智的,如果等待的线程可以在某种程度上睡觉或处于非活动状态,直到它接收它正在等待信号。 + +Java有一个内置的等待机制,使主题变得不活跃,同时等待信号。本类java.lang.Object定义了三个方法,等(),通知()和notifyAll(),以方便这一点。 + +调用wait()有任何对象的线程处于非活动状态,直到另一个线程调用notify()的对象。为了调用或者等待()或通知调用线程必须首先获得该对象的锁。换句话说,调用线程必须调用wait()或通知()从一个同步块内。这里是MySignal的使用等()和notify()修改后的版本称为MyWaitNotify。 + + ```Java public class MonitorObject{ } From c13c0c5bd035a57756c03de755de3c6e3e3b8024 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 17:17:45 +0800 Subject: [PATCH 154/524] Published with https://stackedit.io/ --- .../09.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index 22f9f38..a38d4b0 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -42,10 +42,9 @@ while(!sharedSignal.hasDataToProcess()){ 忙等待对计算机的CPU利用率并不友好,除非平均等待时间十分短暂。更好的做法是,让等待的线程处于休眠状态或非活动状态直至它收到信号。 +Java内置了等待机制可以让线程处于非活动状态直至收到信号。`java.lang.Object`中定义了三个方法:**wait()**,**notify()**和**notifyAll**用来实现这个机制。 -Java has a builtin wait mechanism that enable threads to become inactive while waiting for signals. The class java.lang.Object defines three methods, wait(), notify(), and notifyAll(), to facilitate this. - A thread that calls wait() on any object becomes inactive until another thread calls notify() on that object. In order to call either wait() or notify the calling thread must first obtain the lock on that object. In other words, the calling thread must call wait() or notify() from inside a synchronized block. Here is a modified version of MySignal called MyWaitNotify that uses wait() and notify(). 忙等待是没有运行的等待线程,但如果把平均轮候时间是非常少的CPU在电脑中的一个非常有效的利用。否则,这将是更明智的,如果等待的线程可以在某种程度上睡觉或处于非活动状态,直到它接收它正在等待信号。 From 0a925f6c53052b4a11bcc3ac73405a9ed28cbb57 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 17:39:42 +0800 Subject: [PATCH 155/524] Published with https://stackedit.io/ --- ...347\272\277\347\250\213\351\200\232\344\277\241.md" | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index a38d4b0..da45ef4 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -44,15 +44,7 @@ while(!sharedSignal.hasDataToProcess()){ Java内置了等待机制可以让线程处于非活动状态直至收到信号。`java.lang.Object`中定义了三个方法:**wait()**,**notify()**和**notifyAll**用来实现这个机制。 - -A thread that calls wait() on any object becomes inactive until another thread calls notify() on that object. In order to call either wait() or notify the calling thread must first obtain the lock on that object. In other words, the calling thread must call wait() or notify() from inside a synchronized block. Here is a modified version of MySignal called MyWaitNotify that uses wait() and notify(). - -忙等待是没有运行的等待线程,但如果把平均轮候时间是非常少的CPU在电脑中的一个非常有效的利用。否则,这将是更明智的,如果等待的线程可以在某种程度上睡觉或处于非活动状态,直到它接收它正在等待信号。 - -Java有一个内置的等待机制,使主题变得不活跃,同时等待信号。本类java.lang.Object定义了三个方法,等(),通知()和notifyAll(),以方便这一点。 - -调用wait()有任何对象的线程处于非活动状态,直到另一个线程调用notify()的对象。为了调用或者等待()或通知调用线程必须首先获得该对象的锁。换句话说,调用线程必须调用wait()或通知()从一个同步块内。这里是MySignal的使用等()和notify()修改后的版本称为MyWaitNotify。 - +在线程内部调用任意对象的`wait()`会使该线程变成暂停状态,直到其他线程调用同一个对象的`notify()`或`notifyAll()`方法。如果想要调用对象的wait()/notify()方法,线程先必须取的该对象的同步锁。换言之,**wait()和notify()方法的调用必须在同步代码内部**。上面例子的wait()/notify()版本: ```Java public class MonitorObject{ From 51d7d6c6411f7850807b39fc4c7ff05c87638efa Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 17:41:33 +0800 Subject: [PATCH 156/524] Published with https://stackedit.io/ --- .../09.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index da45ef4..f2aec15 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -70,6 +70,8 @@ public class MyWaitNotify{ } ``` + + The waiting thread would call doWait(), and the notifying thread would call doNotify(). When a thread calls notify() on an object, one of the threads waiting on that object are awakened and allowed to execute. There is also a notifyAll() method that will wake all threads waiting on a given object. As you can see both the waiting and notifying thread calls wait() and notify() from within a synchronized block. This is mandatory! A thread cannot call wait(), notify() or notifyAll() without holding the lock on the object the method is called on. If it does, an IllegalMonitorStateException is thrown. From 763536e755e88b1ccb9c59ca646ffeb2b1fe76f9 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 12 Sep 2014 17:50:38 +0800 Subject: [PATCH 157/524] Published with https://stackedit.io/ --- .../09.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index f2aec15..b2353a7 100644 --- "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -70,7 +70,7 @@ public class MyWaitNotify{ } ``` - +等待通知的线程调用`doWait()`方法,而通知线程调用`doNotify()`方法。当一个线程调用一个对象的`notify()`方法后,等待这个对象的其中一个线程就被唤醒并执行。与`notify()`方法不同的是,`notifyAll()`会唤醒所有等待这个对象的线程。 The waiting thread would call doWait(), and the notifying thread would call doNotify(). When a thread calls notify() on an object, one of the threads waiting on that object are awakened and allowed to execute. There is also a notifyAll() method that will wake all threads waiting on a given object. From a755c07ce67a262442f627ea2610f887b52c4423 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 00:58:27 +0800 Subject: [PATCH 158/524] rename directory --- ...45\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" | 0 ...47\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" | 0 ...47\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" | 0 ...22\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" | 0 ...44\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" | 0 ...44\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" | 0 ...45\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" | 0 .../08.Java\345\220\214\346\255\245\345\235\227" | 0 .../08.Java\345\220\214\346\255\245\345\235\227.md" | 0 .../09.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 0 .../10.\346\255\273\351\224\201.md" | 0 {Java-Concurrency-Multithreading => Java-Concurrency}/README.md | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename "Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" => "Java-Concurrency/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" (100%) rename "Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" => "Java-Concurrency/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" (100%) rename "Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" => "Java-Concurrency/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" (100%) rename "Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" => "Java-Concurrency/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" (100%) rename "Java-Concurrency-Multithreading/05.\347\253\236\346\200\201\346\235\241\344\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" => "Java-Concurrency/05.\347\253\236\346\200\201\346\235\241\344\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" (100%) rename "Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" => "Java-Concurrency/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" (100%) rename "Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" => "Java-Concurrency/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" (100%) rename "Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" => "Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227" (100%) rename "Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" => "Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" (100%) rename "Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" => "Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" (100%) rename "Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" => "Java-Concurrency/10.\346\255\273\351\224\201.md" (100%) rename {Java-Concurrency-Multithreading => Java-Concurrency}/README.md (100%) diff --git "a/Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" "b/Java-Concurrency/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" similarity index 100% rename from "Java-Concurrency-Multithreading/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" rename to "Java-Concurrency/01.Java \345\271\266\345\217\221\344\270\216\345\244\232\347\272\277\347\250\213.md" diff --git "a/Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" "b/Java-Concurrency/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" similarity index 100% rename from "Java-Concurrency-Multithreading/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" rename to "Java-Concurrency/02.\345\244\232\347\272\277\347\250\213\347\232\204\345\245\275\345\244\204.md" diff --git "a/Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" "b/Java-Concurrency/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" similarity index 100% rename from "Java-Concurrency-Multithreading/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" rename to "Java-Concurrency/03.\345\244\232\347\272\277\347\250\213\347\232\204\346\210\220\346\234\254.md" diff --git "a/Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" "b/Java-Concurrency/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" similarity index 100% rename from "Java-Concurrency-Multithreading/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" rename to "Java-Concurrency/04.\345\210\233\345\273\272\345\222\214\345\220\257\345\212\250Java\347\272\277\347\250\213.md" diff --git "a/Java-Concurrency-Multithreading/05.\347\253\236\346\200\201\346\235\241\344\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" "b/Java-Concurrency/05.\347\253\236\346\200\201\346\235\241\344\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" similarity index 100% rename from "Java-Concurrency-Multithreading/05.\347\253\236\346\200\201\346\235\241\344\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" rename to "Java-Concurrency/05.\347\253\236\346\200\201\346\235\241\344\273\266\345\222\214\344\270\264\347\225\214\345\214\272.md" diff --git "a/Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" "b/Java-Concurrency/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" similarity index 100% rename from "Java-Concurrency-Multithreading/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" rename to "Java-Concurrency/06.\347\272\277\347\250\213\345\256\211\345\205\250\344\270\216\350\265\204\346\272\220\345\205\261\344\272\253.md" diff --git "a/Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" "b/Java-Concurrency/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" similarity index 100% rename from "Java-Concurrency-Multithreading/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" rename to "Java-Concurrency/07.\347\272\277\347\250\213\345\256\211\345\205\250\345\222\214\344\270\215\345\217\230\346\200\247.md" diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" "b/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227" similarity index 100% rename from "Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227" rename to "Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227" diff --git "a/Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" "b/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" similarity index 100% rename from "Java-Concurrency-Multithreading/08.Java\345\220\214\346\255\245\345\235\227.md" rename to "Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" diff --git "a/Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" similarity index 100% rename from "Java-Concurrency-Multithreading/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" rename to "Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" diff --git "a/Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" "b/Java-Concurrency/10.\346\255\273\351\224\201.md" similarity index 100% rename from "Java-Concurrency-Multithreading/10.\346\255\273\351\224\201.md" rename to "Java-Concurrency/10.\346\255\273\351\224\201.md" diff --git a/Java-Concurrency-Multithreading/README.md b/Java-Concurrency/README.md similarity index 100% rename from Java-Concurrency-Multithreading/README.md rename to Java-Concurrency/README.md From b6a4ddc406d33d391be6041838e176e439b3e1cf Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 01:08:42 +0800 Subject: [PATCH 159/524] Published with https://stackedit.io/ From 709313d6f6e6610bd3350b7ef31e2665fe3075ff Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 02:23:32 +0800 Subject: [PATCH 160/524] Published with https://stackedit.io/ --- ...9.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index b2353a7..11f2071 100644 --- "a/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -72,15 +72,13 @@ public class MyWaitNotify{ 等待通知的线程调用`doWait()`方法,而通知线程调用`doNotify()`方法。当一个线程调用一个对象的`notify()`方法后,等待这个对象的其中一个线程就被唤醒并执行。与`notify()`方法不同的是,`notifyAll()`会唤醒所有等待这个对象的线程。 -The waiting thread would call doWait(), and the notifying thread would call doNotify(). When a thread calls notify() on an object, one of the threads waiting on that object are awakened and allowed to execute. There is also a notifyAll() method that will wake all threads waiting on a given object. - -As you can see both the waiting and notifying thread calls wait() and notify() from within a synchronized block. This is mandatory! A thread cannot call wait(), notify() or notifyAll() without holding the lock on the object the method is called on. If it does, an IllegalMonitorStateException is thrown. +正如你所看到的,`wait()`和`notify()`的调用都在同步块中。这是强制性的要求。如果线程没有拥有对象的锁,则不能调用该对象的`wait()`,`notify()`和`notifyAll()`方法,否则将会抛出`IlleageMonitorStateException` 异常。 But, how is this possible? Wouldn't the waiting thread keep the lock on the monitor object (myMonitorObject) as long as it is executing inside a synchronized block? Will the waiting thread not block the notifying thread from ever entering the synchronized block in doNotify()? The answer is no. Once a thread calls wait() it releases the lock it holds on the monitor object. This allows other threads to call wait() or notify() too, since these methods must be called from inside a synchronized block. -Once a thread is awakened it cannot exit the wait() call until the thread calling notify() has left its synchronized block. In other words: The awakened thread must reobtain the lock on the monitor object before it can exit the wait() call, because the wait call is nested inside a synchronized block. If multiple threads are awakened using notifyAll() only one awakened thread at a time can exit the wait() method, since each thread must obtain the lock on the monitor object in turn before exiting wait(). +当一个等待的线程被唤醒之后并不会立即离开`wait()`方法直至调用`notify()`方法的线程退出代码块。换言之,因为`wait()`方法嵌套在同步代码块内部,所以被唤醒的线程需要重新获得模拟器对象的锁才能够离开`wait()`方法。如果有多个线程通过`notifyAll()`方法被唤醒,同一时间也只能有一个线程能够离开`wait()`方法并重新进入同步代码块,因为每一个线程都必须先获得模拟器对象的锁才能够离开`wait()`方法。 -##Missed Signals +##错过的信号(Missed Signals) The methods notify() and notifyAll() do not save the method calls to them in case no threads are waiting when they are called. The notify signal is then just lost. Therefore, if a thread calls notify() before the thread to signal has called wait(), the signal will be missed by the waiting thread. This may or may not be a problem, but in some cases this may result in the waiting thread waiting forever, never waking up, because the signal to wake up was missed. From 5383e30ddcd29444b6dd5858dc92f6a0ff937961 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 03:34:33 +0800 Subject: [PATCH 161/524] Published with https://stackedit.io/ --- .../09.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index 11f2071..b63cb40 100644 --- "a/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -78,10 +78,12 @@ But, how is this possible? Wouldn't the waiting thread keep the lock on the moni 当一个等待的线程被唤醒之后并不会立即离开`wait()`方法直至调用`notify()`方法的线程退出代码块。换言之,因为`wait()`方法嵌套在同步代码块内部,所以被唤醒的线程需要重新获得模拟器对象的锁才能够离开`wait()`方法。如果有多个线程通过`notifyAll()`方法被唤醒,同一时间也只能有一个线程能够离开`wait()`方法并重新进入同步代码块,因为每一个线程都必须先获得模拟器对象的锁才能够离开`wait()`方法。 -##错过的信号(Missed Signals) +##信号丢失(Missed Signals) The methods notify() and notifyAll() do not save the method calls to them in case no threads are waiting when they are called. The notify signal is then just lost. Therefore, if a thread calls notify() before the thread to signal has called wait(), the signal will be missed by the waiting thread. This may or may not be a problem, but in some cases this may result in the waiting thread waiting forever, never waking up, because the signal to wake up was missed. +该方法的通知()和notifyAll()不救的方法调用它们的情况下没有线程在等待的时候,他们被称为。该通知信号然后就失去了。因此,如果一个线程调用notify()的线程之前,信号调用wait()时,信号将被等待的线程被错过。这可能会或可能不会成为问题,但在某些情况下,这可能会导致等待线程永远等待,从未苏醒,因为该信号被错过醒来。 + To avoid losing signals they should be stored inside the signal class. In the MyWaitNotify example the notify signal should be stored in a member variable inside the MyWaitNotify instance. Here is a modified version of MyWaitNotify that does this: ```Java From 2598da3e4feda5e3e892e07fe414dbba4e9db8a9 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 04:26:12 +0800 Subject: [PATCH 162/524] Published with https://stackedit.io/ --- .../09.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" index b63cb40..126f4a0 100644 --- "a/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -115,7 +115,7 @@ public class MyWaitNotify2{ Notice how the doNotify() method now sets the wasSignalled variable to true before calling notify(). Also, notice how the doWait() method now checks the wasSignalled variable before calling wait(). In fact it only calls wait() if no signal was received in between the previous doWait() call and this. -##Spurious Wakeups +##假唤醒(Spurious Wakeups) For inexplicable reasons it is possible for threads to wake up even if notify() and notifyAll() has not been called. This is known as spurious wakeups. Wakeups without any reason. From 6f37e1cb710dda39291916da791bc331aa65aaf2 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 15:33:49 +0800 Subject: [PATCH 163/524] Published with https://stackedit.io/ From 33c35c3324e5a3d7336cb4fd564c19a743c0b94d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 15:35:04 +0800 Subject: [PATCH 164/524] Published with https://stackedit.io/ From d73e88e920a3573ddd7a379c4f39acb6bf5805c7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 15:36:14 +0800 Subject: [PATCH 165/524] Published with https://stackedit.io/ --- "Java-Concurrency/10.\346\255\273\351\224\201.md" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/Java-Concurrency/10.\346\255\273\351\224\201.md" "b/Java-Concurrency/10.\346\255\273\351\224\201.md" index b28a67e..10543a1 100644 --- "a/Java-Concurrency/10.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/10.\346\255\273\351\224\201.md" @@ -5,10 +5,12 @@ A deadlock is when two or more threads are blocked waiting to obtain locks that For instance, if thread 1 locks A, and tries to lock B, and thread 2 has already locked B, and tries to lock A, a deadlock arises. Thread 1 can never get B, and thread 2 can never get A. In addition, neither of them will ever know. They will remain blocked on each their object, A and B, forever. This situation is a deadlock. The situation is illustrated below: + ``` Thread 1 locks A, waits for B Thread 2 locks B, waits for A ``` + Here is an example of a TreeNode class that call synchronized methods in different instances: ```Java From 59028173e3a9bf4db1fe5a4c1b7283e6458a48ca Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 15:36:20 +0800 Subject: [PATCH 166/524] Published with https://stackedit.io/ From b1571689af66ebd19d86a81ba76377e93a222d25 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 17:15:13 +0800 Subject: [PATCH 167/524] Published with https://stackedit.io/ --- "Java-Concurrency/10.\346\255\273\351\224\201.md" | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git "a/Java-Concurrency/10.\346\255\273\351\224\201.md" "b/Java-Concurrency/10.\346\255\273\351\224\201.md" index 10543a1..071f43c 100644 --- "a/Java-Concurrency/10.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/10.\346\255\273\351\224\201.md" @@ -1,21 +1,20 @@ #10.死锁 -A deadlock is when two or more threads are blocked waiting to obtain locks that some of the other threads in the deadlock are holding. Deadlock can occur when multiple threads need the same locks, at the same time, but obtain them in different order. +死锁是指两个或多个线程等待其他处于死锁状态的线程所持有的锁。死锁通常发生在多个线程同时但以不同的顺序请求同一组锁的时候。 -For instance, if thread 1 locks A, and tries to lock B, and thread 2 has already locked B, and tries to lock A, a deadlock arises. Thread 1 can never get B, and thread 2 can never get A. In addition, neither of them will ever know. They will remain blocked on each their object, A and B, forever. This situation is a deadlock. +例如,如果线程1持有锁A,但试图去获取锁B,而此时线程1持有锁B,却试图去获取锁A,这时死锁就发生了。线程1永远得不到锁B,线程2也永远得不到线程A,并且它们永远也不知道发生了什么事。为了获得彼此所持有的锁,它们将永远阻塞下去。这种情况就是一个死锁。 -The situation is illustrated below: +这种情况描述如下: ``` Thread 1 locks A, waits for B Thread 2 locks B, waits for A ``` -Here is an example of a TreeNode class that call synchronized methods in different instances: +这里有一个TreeNode类的例子,它调用了不同实例的synchronized方法: ```Java public class TreeNode { - TreeNode parent = null; List children = new ArrayList(); @@ -43,7 +42,9 @@ public class TreeNode { } ``` -If a thread (1) calls the parent.addChild(child) method at the same time as another thread (2) calls the child.setParent(parent) method, on the same parent and child instances, a deadlock can occur. Here is some pseudo code that illustrates this: + 如果线程1调用`parent.addChild(child)`方法,而与此同时线程2调用`child.setParent(parent)`方法,两个线程中的parent和child都是同一个对象实例,此时死锁就发生了。 + +下面的伪代码说明了这个过程: ``` Thread 1: parent.addChild(child); //locks parent From 200f42e500f8da636f5a8b460864be007fb0f3a7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 17:25:51 +0800 Subject: [PATCH 168/524] Published with https://stackedit.io/ --- "Java-Concurrency/10.\346\255\273\351\224\201.md" | 4 ++++ 1 file changed, 4 insertions(+) diff --git "a/Java-Concurrency/10.\346\255\273\351\224\201.md" "b/Java-Concurrency/10.\346\255\273\351\224\201.md" index 071f43c..47209cf 100644 --- "a/Java-Concurrency/10.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/10.\346\255\273\351\224\201.md" @@ -54,6 +54,10 @@ Thread 2: child.setParent(parent); //locks child --> parent.addChildOnly() ``` +首先线程1调用`parent.addChild(child)`方法,由于这个方法是同步的,所以线程1锁住了parent对象以防止其他线程访问。 + +然后线程2调用`child.setParent(parent)`方法,由于这个方法的同步的,所以线程2锁住了child对象以防止其他线程访问。 + First thread 1 calls parent.addChild(child). Since addChild() is synchronized thread 1 effectively locks the parent object for access from other treads. Then thread 2 calls child.setParent(parent). Since setParent() is synchronized thread 2 effectively locks the child object for acces from other threads. From b54c28260e234fd85577b4aad245aa7ca3224800 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 17:37:01 +0800 Subject: [PATCH 169/524] Published with https://stackedit.io/ --- "Java-Concurrency/10.\346\255\273\351\224\201.md" | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git "a/Java-Concurrency/10.\346\255\273\351\224\201.md" "b/Java-Concurrency/10.\346\255\273\351\224\201.md" index 47209cf..465d411 100644 --- "a/Java-Concurrency/10.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/10.\346\255\273\351\224\201.md" @@ -58,11 +58,7 @@ Thread 2: child.setParent(parent); //locks child 然后线程2调用`child.setParent(parent)`方法,由于这个方法的同步的,所以线程2锁住了child对象以防止其他线程访问。 -First thread 1 calls parent.addChild(child). Since addChild() is synchronized thread 1 effectively locks the parent object for access from other treads. - -Then thread 2 calls child.setParent(parent). Since setParent() is synchronized thread 2 effectively locks the child object for acces from other threads. - -Now both child and parent objects are locked by two different threads. Next thread 1 tries to call child.setParentOnly() method, but the child object is locked by thread 2, so the method call just blocks. Thread 2 also tries to call parent.addChildOnly() but the parent object is locked by thread 1, causing thread 2 to block on that method call. Now both threads are blocked waiting to obtain locks the other thread holds. +现在parent对象和child对象都分别被线程1和线程2锁住了。下一步,线程1试图调用`child.setParentOnly()`方法,但child方法已经被线程2锁住,所以这个方法会阻塞。线程2也试图调用`parent.addChildOnly()`方法,但parent对象此时已被线程1锁住,所以这个方法也会阻塞。现在两个线程都试图获取对方所持有的锁而进入阻塞状态。 Note: The two threads must call parent.addChild(child) and child.setParent(parent) at the same time as described above, and on the same two parent and child instances for a deadlock to occur. The code above may execute fine for a long time until all of a sudden it deadlocks. From 3b53bf6292c6b7373f2782d19304173ed9550313 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 18:10:55 +0800 Subject: [PATCH 170/524] Published with https://stackedit.io/ --- "Java-Concurrency/10.\346\255\273\351\224\201.md" | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git "a/Java-Concurrency/10.\346\255\273\351\224\201.md" "b/Java-Concurrency/10.\346\255\273\351\224\201.md" index 465d411..6b39892 100644 --- "a/Java-Concurrency/10.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/10.\346\255\273\351\224\201.md" @@ -60,10 +60,9 @@ Thread 2: child.setParent(parent); //locks child 现在parent对象和child对象都分别被线程1和线程2锁住了。下一步,线程1试图调用`child.setParentOnly()`方法,但child方法已经被线程2锁住,所以这个方法会阻塞。线程2也试图调用`parent.addChildOnly()`方法,但parent对象此时已被线程1锁住,所以这个方法也会阻塞。现在两个线程都试图获取对方所持有的锁而进入阻塞状态。 -Note: The two threads must call parent.addChild(child) and child.setParent(parent) at the same time as described above, and on the same two parent and child instances for a deadlock to occur. The code above may execute fine for a long time until all of a sudden it deadlocks. - -The threads really need to take the locks *at the same time*. For instance, if thread 1 is a bit ahead of thread2, and thus locks both A and B, then thread 2 will be blocked already when trying to lock B. Then no deadlock occurs. Since thread scheduling often is unpredictable there is no way to predict *when* a deadlock occurs. Only that it *can* occur. +注意:两个线程必须同时调用`parent.addChild(child)`和`child.setParent(parent)`方法,而且并需是在同一个parent和child对象上,死锁才有可能发生。上面的代码可能要运行一段时间才可能出现死锁。 +这两个线程必须要同时获得锁。举个例子,如果线程1稍微先与线程2获得A和B的锁,这时线程2在试图获取B的锁时就会阻塞,这时不会产生死锁。由于线程的调度不可预测,所以我们无法预测什么时候会产生死锁,仅仅是可能会发生。 ##More Complicated Deadlocks From 026c00a8533f55314a3f3b0e719d54b31226b4fd Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 18:13:10 +0800 Subject: [PATCH 171/524] Published with https://stackedit.io/ --- "Java-Concurrency/10.\346\255\273\351\224\201.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/10.\346\255\273\351\224\201.md" "b/Java-Concurrency/10.\346\255\273\351\224\201.md" index 6b39892..d397274 100644 --- "a/Java-Concurrency/10.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/10.\346\255\273\351\224\201.md" @@ -64,7 +64,7 @@ Thread 2: child.setParent(parent); //locks child 这两个线程必须要同时获得锁。举个例子,如果线程1稍微先与线程2获得A和B的锁,这时线程2在试图获取B的锁时就会阻塞,这时不会产生死锁。由于线程的调度不可预测,所以我们无法预测什么时候会产生死锁,仅仅是可能会发生。 -##More Complicated Deadlocks +##更加复杂的死锁(More Complicated Deadlocks) Deadlock can also include more than two threads. This makes it harder to detect. Here is an example in which four threads have deadlocked: ``` From a28e2a99d1d90b94a1d6dc340ac972d7ce6cbad7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 18:15:59 +0800 Subject: [PATCH 172/524] Published with https://stackedit.io/ --- "Java-Concurrency/10.\346\255\273\351\224\201.md" | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/10.\346\255\273\351\224\201.md" "b/Java-Concurrency/10.\346\255\273\351\224\201.md" index d397274..f08d8b4 100644 --- "a/Java-Concurrency/10.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/10.\346\255\273\351\224\201.md" @@ -66,16 +66,19 @@ Thread 2: child.setParent(parent); //locks child ##更加复杂的死锁(More Complicated Deadlocks) -Deadlock can also include more than two threads. This makes it harder to detect. Here is an example in which four threads have deadlocked: +死锁的发生可能由多于两个线程造成,在这种情况下,很难对死锁进行检测。下面的例子演示了多个线程造成的死锁: + ``` Thread 1 locks A, waits for B Thread 2 locks B, waits for C Thread 3 locks C, waits for D Thread 4 locks D, waits for A ``` + +线程1等待线程2,线程2等待线程3,线程3等待线程4,而线程4等待线程1. Thread 1 waits for thread 2, thread 2 waits for thread 3, thread 3 waits for thread 4, and thread 4 waits for thread 1. -##Database Deadlocks +##数据库死锁(Database Deadlocks) A more complicated situation in which deadlocks can occur, is a database transaction. A database transaction may consist of many SQL update requests. When a record is updated during a transaction, that record is locked for updates from other transactions, until the first transaction completes. Each update request within the same transaction may therefore lock some records in the database. @@ -83,6 +86,8 @@ If multiple transactions are running at the same time that need to update the sa For example +举个例子: + ``` Transaction 1, request 1, locks record 1 for update Transaction 2, request 1, locks record 2 for update From 5fc2f91a00f1fa0178eb07e8cbe4de47290998b4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 18:48:30 +0800 Subject: [PATCH 173/524] Published with https://stackedit.io/ --- "Java-Concurrency/10.\346\255\273\351\224\201.md" | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/10.\346\255\273\351\224\201.md" "b/Java-Concurrency/10.\346\255\273\351\224\201.md" index f08d8b4..be1ac0a 100644 --- "a/Java-Concurrency/10.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/10.\346\255\273\351\224\201.md" @@ -80,11 +80,9 @@ Thread 1 waits for thread 2, thread 2 waits for thread 3, thread 3 waits for thr ##数据库死锁(Database Deadlocks) -A more complicated situation in which deadlocks can occur, is a database transaction. A database transaction may consist of many SQL update requests. When a record is updated during a transaction, that record is locked for updates from other transactions, until the first transaction completes. Each update request within the same transaction may therefore lock some records in the database. +更加复杂的死锁场景发生在数据库中。一个数据库事务通常包含多条SQL更新请求。当一条记录被事务更新时,这条记录就会被这个事务锁住,以防止其他事务更新,直到当前事务结束。同一个事务中的多个更新语句都有可能需要锁住一些记录。 -If multiple transactions are running at the same time that need to update the same records, there is a risk of them ending up in a deadlock. - -For example +当多个事务同时需要对一些相同的记录做更新操作时,就很有可能发生死锁,例如: 举个例子: @@ -95,4 +93,4 @@ Transaction 1, request 2, tries to lock record 2 for update. Transaction 2, request 2, tries to lock record 1 for update. ``` -Since the locks are taken in different requests, and not all locks needed for a given transaction are known ahead of time, it is hard to detect or prevent deadlocks in database transactions. \ No newline at end of file +因为锁发生在不同的请求中,并且对于一个事务来说不可能提前知道所有它需要的锁,因此很难检测和避免数据库事务中的死锁。 \ No newline at end of file From 34b3d3a0adff2b97b274b0f1d0f273391625b069 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 13 Sep 2014 18:54:18 +0800 Subject: [PATCH 174/524] Published with https://stackedit.io/ --- ...04\351\230\262\346\255\273\351\224\201.md" | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 "Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" diff --git "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" new file mode 100644 index 0000000..919878b --- /dev/null +++ "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" @@ -0,0 +1,92 @@ +#11.预防死锁 + +In some situations it is possible to prevent deadlocks. I'll describe three techniques in this text: + +Lock Ordering +Lock Timeout +Deadlock Detection + + +##Lock Ordering + +Deadlock occurs when multiple threads need the same locks but obtain them in different order. + +If you make sure that all locks are always taken in the same order by any thread, deadlocks cannot occur. Look at this example: + +``` +Thread 1: + + lock A + lock B + + +Thread 2: + + wait for A + lock C (when A locked) + + +Thread 3: + + wait for A + wait for B + wait for C +``` + +If a thread, like Thread 3, needs several locks, it must take them in the decided order. It cannot take a lock later in the sequence until it has obtained the earlier locks. + +For instance, neither Thread 2 or Thread 3 can lock C until they have locked A first. Since Thread 1 holds lock A, Thread 2 and 3 must first wait until lock A is unlocked. Then they must succeed in locking A, before they can attempt to lock B or C. + +Lock ordering is a simple yet effective deadlock prevention mechanism. However, it can only be used if you know about all locks needed ahead of taking any of the locks. This is not always the case. + +##Lock Timeout + +Another deadlock prevention mechanism is to put a timeout on lock attempts meaning a thread trying to obtain a lock will only try for so long before giving up. If a thread does not succeed in taking all necessary locks within the given timeout, it will backup, free all locks taken, wait for a random amount of time and then retry. The random amount of time waited serves to give other threads trying to take the same locks a chance to take all locks, and thus let the application continue running without locking. + +Here is an example of two threads trying to take the same two locks in different order, where the threads back up and retry: + +``` +Thread 1 locks A +Thread 2 locks B + +Thread 1 attempts to lock B but is blocked +Thread 2 attempts to lock A but is blocked + +Thread 1's lock attempt on B times out +Thread 1 backs up and releases A as well +Thread 1 waits randomly (e.g. 257 millis) before retrying. + +Thread 2's lock attempt on A times out +Thread 2 backs up and releases B as well +Thread 2 waits randomly (e.g. 43 millis) before retrying. +``` + +In the above example Thread 2 will retry taking the locks about 200 millis before Thread 1 and will therefore likely succeed at taking both locks. Thread 1 will then wait already trying to take lock A. When Thread 2 finishes, Thread 1 will be able to take both locks too (unless Thread 2 or another thread takes the locks in between). + +An issue to keep in mind is, that just because a lock times out it does not necessarily mean that the threads had deadlocked. It could also just mean that the thread holding the lock (causing the other thread to time out) takes a long time to complete its task. + +Additionally, if enough threads compete for the same resources they still risk trying to take the threads at the same time again and again, even if timing out and backing up. This may not occur with 2 threads each waiting between 0 and 500 millis before retrying, but with 10 or 20 threads the situation is different. Then the likeliness of two threads waiting the same time before retrying (or close enough to cause problems) is a lot higher. + +A problem with the lock timeout mechanism is that it is not possible to set a timeout for entering a synchronized block in Java. You will have to create a custom lock class or use one of the Java 5 concurrency constructs in the java.util.concurrency package. Writing custom locks isn't difficult but it is outside the scope of this text. Later texts in the Java concurrency trails will cover custom locks. + +#Deadlock Detection + +Deadlock detection is a heavier deadlock prevention mechanism aimed at cases in which lock ordering isn't possible, and lock timeout isn't feasible. + +Every time a thread takes a lock it is noted in a data structure (map, graph etc.) of threads and locks. Additionally, whenever a thread requests a lock this is also noted in this data structure. + +When a thread requests a lock but the request is denied, the thread can traverse the lock graph to check for deadlocks. For instance, if a Thread A requests lock 7, but lock 7 is held by Thread B, then Thread A can check if Thread B has requested any of the locks Thread A holds (if any). If Thread B has requested so, a deadlock has occurred (Thread A having taken lock 1, requesting lock 7, Thread B having taken lock 7, requesting lock 1). + +Of course a deadlock scenario may be a lot more complicated than two threads holding each others locks. Thread A may wait for Thread B, Thread B waits for Thread C, Thread C waits for Thread D, and Thread D waits for Thread A. In order for Thread A to detect a deadlock it must transitively examine all requested locks by Thread B. From Thread B's requested locks Thread A will get to Thread C, and then to Thread D, from which it finds one of the locks Thread A itself is holding. Then it knows a deadlock has occurred. + +Below is a graph of locks taken and requested by 4 threads (A, B, C and D). A data structure like this that can be used to detect deadlocks. + +Deadlock Detection Data Structure + + + +So what do the threads do if a deadlock is detected? + +One possible action is to release all locks, backup, wait a random amount of time and then retry. This is similar to the simpler lock timeout mechanism except threads only backup when a deadlock has actually occurred. Not just because their lock requests timed out. However, if a lot of threads are competing for the same locks they may repeatedly end up in a deadlock even if they back up and wait. + +A better option is to determine or assign a priority of the threads so that only one (or a few) thread backs up. The rest of the threads continue taking the locks they need as if no deadlock had occurred. If the priority assigned to the threads is fixed, the same threads will always be given higher priority. To avoid this you may assign the priority randomly whenever a deadlock is detected. \ No newline at end of file From 16aa72aa720cd23e5c79d3859f0ae7dc3ac8dfb2 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 00:01:29 +0800 Subject: [PATCH 175/524] Published with https://stackedit.io/ --- ...351\242\204\351\230\262\346\255\273\351\224\201.md" | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" index 919878b..930a45c 100644 --- "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" @@ -1,13 +1,13 @@ #11.预防死锁 -In some situations it is possible to prevent deadlocks. I'll describe three techniques in this text: +在某些情况,死锁是可以预防的。下面介绍三种可以预防死锁的技术: -Lock Ordering -Lock Timeout -Deadlock Detection +* 加锁顺序 +* 加锁时限 +* 死锁检测 -##Lock Ordering +##加锁顺序(Lock Ordering) Deadlock occurs when multiple threads need the same locks but obtain them in different order. From eae525d13db23086cd14e4e09db99cbdd81e0ae9 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 00:17:48 +0800 Subject: [PATCH 176/524] Published with https://stackedit.io/ --- ...351\242\204\351\230\262\346\255\273\351\224\201.md" | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" index 930a45c..42b8d75 100644 --- "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" @@ -9,23 +9,21 @@ ##加锁顺序(Lock Ordering) -Deadlock occurs when multiple threads need the same locks but obtain them in different order. +当多个线程需要相同的锁,但以不同的顺序获取锁时,这时死锁就很容易发生。 -If you make sure that all locks are always taken in the same order by any thread, deadlocks cannot occur. Look at this example: +如果所有的锁都是按照相同的顺序获取,那么死锁是不会出现的。看下下面的例子: ``` Thread 1: lock A lock B - - +--------------------- Thread 2: wait for A lock C (when A locked) - - +--------------------- Thread 3: wait for A From 08e261a6250b5c719aff80b701b3f3135d59e2aa Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 00:45:08 +0800 Subject: [PATCH 177/524] Published with https://stackedit.io/ --- ...51\242\204\351\230\262\346\255\273\351\224\201.md" | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" index 42b8d75..bad470c 100644 --- "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" @@ -3,7 +3,7 @@ 在某些情况,死锁是可以预防的。下面介绍三种可以预防死锁的技术: * 加锁顺序 -* 加锁时限 +* 加锁超时 * 死锁检测 @@ -31,13 +31,14 @@ Thread 3: wait for C ``` -If a thread, like Thread 3, needs several locks, it must take them in the decided order. It cannot take a lock later in the sequence until it has obtained the earlier locks. +如果一个线程,例如线程3,需要一些锁,那么她必须按照一定的顺序获取锁。只有按照顺序获取前面的锁,才能够依次获取后面的锁。 -For instance, neither Thread 2 or Thread 3 can lock C until they have locked A first. Since Thread 1 holds lock A, Thread 2 and 3 must first wait until lock A is unlocked. Then they must succeed in locking A, before they can attempt to lock B or C. +例如,线程2和线程3,只有当它们获得锁A后才能够去尝试获取锁C。由于线程1持有锁A,线程2和线程3都会阻塞直至锁A被线程1释放。 -Lock ordering is a simple yet effective deadlock prevention mechanism. However, it can only be used if you know about all locks needed ahead of taking any of the locks. This is not always the case. +顺序加锁是一个非常有效的用于预防死锁的机制。然而,它只有预先知道所有的加锁顺序时才能很好的地工作,它并不适用于所有情况。(However, it can only be used if you know about all locks needed ahead of taking any of the locks. This is not always the case.) -##Lock Timeout + +##加锁超时(Lock Timeout) Another deadlock prevention mechanism is to put a timeout on lock attempts meaning a thread trying to obtain a lock will only try for so long before giving up. If a thread does not succeed in taking all necessary locks within the given timeout, it will backup, free all locks taken, wait for a random amount of time and then retry. The random amount of time waited serves to give other threads trying to take the same locks a chance to take all locks, and thus let the application continue running without locking. From 765a24993b3aa4777b44f2bedb269832c77104b5 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 01:48:35 +0800 Subject: [PATCH 178/524] Published with https://stackedit.io/ --- ...04\351\230\262\346\255\273\351\224\201.md" | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" index bad470c..83b3dd0 100644 --- "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" @@ -40,9 +40,9 @@ Thread 3: ##加锁超时(Lock Timeout) -Another deadlock prevention mechanism is to put a timeout on lock attempts meaning a thread trying to obtain a lock will only try for so long before giving up. If a thread does not succeed in taking all necessary locks within the given timeout, it will backup, free all locks taken, wait for a random amount of time and then retry. The random amount of time waited serves to give other threads trying to take the same locks a chance to take all locks, and thus let the application continue running without locking. +另一种预防死锁的机制就是试图获取锁时设置超时。如果线程在规定时间内没有获得锁,则会放弃,并释放自身锁持有的锁,等待一个随机时间,然后重试。在随机等待时间内,给予其他线程获取相同的锁,从而避免死锁发生。 -Here is an example of two threads trying to take the same two locks in different order, where the threads back up and retry: +下面是两个线程尝试以不同的顺序获取两个锁,在超时回退后进行重试的例子: ``` Thread 1 locks A @@ -60,6 +60,14 @@ Thread 2 backs up and releases B as well Thread 2 waits randomly (e.g. 43 millis) before retrying. ``` +在上面的例子中,线程2比线程1早大约200ms进行重新加锁,因此很有可能可以取到全部的锁。线程1尝试获取锁A,由于2持有所有A,所以线程1进入等待状态。当线程2执行完释放所有的锁,线程1就可以持有所有的锁了。(除非有其他线程也在争夺锁A和锁B) + +有个问题需要注意的就是,如果出现了加锁超时,并不意味着出现了死锁。加锁超时可能是因为某个持有锁的线程需要大量的时间来执行任务。 + +另外,如果有大量的线程去争夺相同的资源,即使有加锁超时和重试机制,也有可能会导致线程不停地重试但却无法获取所需的锁。如果只有两个线程,且重试时间在0-500ms之间,也许死锁不会发生。但如果线程在10-20之间情况则有可能不同,因为这些线程中的超时重试时间很大概率生是相同或相近的。 + + + In the above example Thread 2 will retry taking the locks about 200 millis before Thread 1 and will therefore likely succeed at taking both locks. Thread 1 will then wait already trying to take lock A. When Thread 2 finishes, Thread 1 will be able to take both locks too (unless Thread 2 or another thread takes the locks in between). An issue to keep in mind is, that just because a lock times out it does not necessarily mean that the threads had deadlocked. It could also just mean that the thread holding the lock (causing the other thread to time out) takes a long time to complete its task. @@ -68,6 +76,14 @@ Additionally, if enough threads compete for the same resources they still risk t A problem with the lock timeout mechanism is that it is not possible to set a timeout for entering a synchronized block in Java. You will have to create a custom lock class or use one of the Java 5 concurrency constructs in the java.util.concurrency package. Writing custom locks isn't difficult but it is outside the scope of this text. Later texts in the Java concurrency trails will cover custom locks. +在上面的例子中,线程2将重试走约200毫锁螺纹1日之前,因此将有可能在服用这两种锁成功。线程1然后等待已经试图把锁A.当线程2结束后,线程1就可以采取两种锁过(除非线程2或另一个线程需要的锁之间)。 + +一个问题需要注意的,那只是因为锁超时并不一定意味着该线程已陷入僵局。它也可能只是意味着线程持有锁(导致其他线程超时)需要很长的时间来完成其任务。 + +此外,如果有足够的线程竞争相同的资源,他们仍然冒险试图采取同时线程连连,即使超时和备份。这可能不是与2个线程在重试之前0和500毫之间相互等待发生,但与10或20个线程的情况是不同的。然后两个线程的likeliness等待的同时重试之前(或非常接近造成的问题)是高了很多。 + +与锁超时机制的一个问题是,它是不是可以设置超时进入Java中的synchronized块。你必须创建一个自定义锁类,或使用在java.util.concurrency包在Java5并发构造之一。编写自定义锁并不难,但它 + #Deadlock Detection Deadlock detection is a heavier deadlock prevention mechanism aimed at cases in which lock ordering isn't possible, and lock timeout isn't feasible. From a2d232e198931b2037f5be210ea73a40e6f65093 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 02:09:34 +0800 Subject: [PATCH 179/524] Published with https://stackedit.io/ --- ...04\351\230\262\346\255\273\351\224\201.md" | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" index 83b3dd0..3f6bcf2 100644 --- "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" @@ -66,25 +66,9 @@ Thread 2 waits randomly (e.g. 43 millis) before retrying. 另外,如果有大量的线程去争夺相同的资源,即使有加锁超时和重试机制,也有可能会导致线程不停地重试但却无法获取所需的锁。如果只有两个线程,且重试时间在0-500ms之间,也许死锁不会发生。但如果线程在10-20之间情况则有可能不同,因为这些线程中的超时重试时间很大概率生是相同或相近的。 +加锁超时机制的一个缺点是:Java并不提供进入synchronized块的超时设置。你可以自定义锁或使用Java 5提供的在`java.util.concurrency`包中的工具类。自定义锁并不困难,但是超出了本文的内容。后面的教程会做详细讲解。 - -In the above example Thread 2 will retry taking the locks about 200 millis before Thread 1 and will therefore likely succeed at taking both locks. Thread 1 will then wait already trying to take lock A. When Thread 2 finishes, Thread 1 will be able to take both locks too (unless Thread 2 or another thread takes the locks in between). - -An issue to keep in mind is, that just because a lock times out it does not necessarily mean that the threads had deadlocked. It could also just mean that the thread holding the lock (causing the other thread to time out) takes a long time to complete its task. - -Additionally, if enough threads compete for the same resources they still risk trying to take the threads at the same time again and again, even if timing out and backing up. This may not occur with 2 threads each waiting between 0 and 500 millis before retrying, but with 10 or 20 threads the situation is different. Then the likeliness of two threads waiting the same time before retrying (or close enough to cause problems) is a lot higher. - -A problem with the lock timeout mechanism is that it is not possible to set a timeout for entering a synchronized block in Java. You will have to create a custom lock class or use one of the Java 5 concurrency constructs in the java.util.concurrency package. Writing custom locks isn't difficult but it is outside the scope of this text. Later texts in the Java concurrency trails will cover custom locks. - -在上面的例子中,线程2将重试走约200毫锁螺纹1日之前,因此将有可能在服用这两种锁成功。线程1然后等待已经试图把锁A.当线程2结束后,线程1就可以采取两种锁过(除非线程2或另一个线程需要的锁之间)。 - -一个问题需要注意的,那只是因为锁超时并不一定意味着该线程已陷入僵局。它也可能只是意味着线程持有锁(导致其他线程超时)需要很长的时间来完成其任务。 - -此外,如果有足够的线程竞争相同的资源,他们仍然冒险试图采取同时线程连连,即使超时和备份。这可能不是与2个线程在重试之前0和500毫之间相互等待发生,但与10或20个线程的情况是不同的。然后两个线程的likeliness等待的同时重试之前(或非常接近造成的问题)是高了很多。 - -与锁超时机制的一个问题是,它是不是可以设置超时进入Java中的synchronized块。你必须创建一个自定义锁类,或使用在java.util.concurrency包在Java5并发构造之一。编写自定义锁并不难,但它 - -#Deadlock Detection +##死锁检测(Deadlock Detection) Deadlock detection is a heavier deadlock prevention mechanism aimed at cases in which lock ordering isn't possible, and lock timeout isn't feasible. From 6fefd0682ba4b435687572cd968b5c8001a2c379 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 02:12:10 +0800 Subject: [PATCH 180/524] Published with https://stackedit.io/ --- ...77\345\222\214\345\205\254\345\271\263.md" | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 "Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" new file mode 100644 index 0000000..f0f7c53 --- /dev/null +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -0,0 +1,172 @@ +#饥饿和公平(Starvation and Fairness) + +If a thread is not granted CPU time because other threads grab it all, it is called "starvation". The thread is "starved to death" because other threads are allowed the CPU time instead of it. The solution to starvation is called "fairness" - that all threads are fairly granted a chance to execute. + +Causes of Starvation in Java + +The following three common causes can lead to starvation of threads in Java: + +Threads with high priority swallow all CPU time from threads with lower priority. + +Threads are blocked indefinately waiting to enter a synchronized block, because other threads are constantly allowed access before it. + +Threads waiting on an object (called wait() on it) remain waiting indefinitely because other threads are constantly awakened instead of it. +Threads with high priority swallow all CPU time from threads with lower priority + +You can set the thread priority of each thread individually. The higher the priority the more CPU time the thread is granted. You can set the priority of threads between 1 and 10. Exactly how this is interpreted depends on the operating system your application is running on. For most applications you are better off leaving the priority unchanged. + +Threads are blocked indefinitely waiting to enter a synchronized block + +Java's synchronized code blocks can be another cause of starvation. Java's synchronized code block makes no guarantee about the sequence in which threads waiting to enter the synchronized block are allowed to enter. This means that there is a theoretical risk that a thread remains blocked forever trying to enter the block, because other threads are constantly granted access before it. This problem is called "starvation", that a thread is "starved to death" by because other threads are allowed the CPU time instead of it. + +Threads waiting on an object (called wait() on it) remain waiting indefinitely + +The notify() method makes no guarantee about what thread is awakened if multiple thread have called wait() on the object notify() is called on. It could be any of the threads waiting. Therefore there is a risk that a thread waiting on a certain object is never awakened because other waiting threads are always awakened instead of it. + +Implementing Fairness in Java + +While it is not possible to implement 100% fairness in Java we can still implement our synchronization constructs to increase fairness between threads. + +First lets study a simple synchronized code block: + +public class Synchronizer{ + + public synchronized void doSynchronized(){ + //do a lot of work which takes a long time + } + +} +If more than one thread call the doSynchronized() method, some of them will be blocked until the first thread granted access has left the method. If more than one thread are blocked waiting for access there is no guarantee about which thread is granted access next. + +Using Locks Instead of Synchronized Blocks + +To increase the fairness of waiting threads first we will change the code block to be guarded by a lock rather than a synchronized block: + +public class Synchronizer{ + Lock lock = new Lock(); + + public void doSynchronized() throws InterruptedException{ + this.lock.lock(); + //critical section, do a lot of work which takes a long time + this.lock.unlock(); + } + +} +Notice how the doSynchronized() method is no longer declared synchronized. Instead the critical section is guarded by the lock.lock() and lock.unlock() calls. + +A simple implementation of the Lock class could look like this: + +public class Lock{ + private boolean isLocked = false; + private Thread lockingThread = null; + + public synchronized void lock() throws InterruptedException{ + while(isLocked){ + wait(); + } + isLocked = true; + lockingThread = Thread.currentThread(); + } + + public synchronized void unlock(){ + if(this.lockingThread != Thread.currentThread()){ + throw new IllegalMonitorStateException( + "Calling thread has not locked this lock"); + } + isLocked = false; + lockingThread = null; + notify(); + } +} +If you look at the Synchronizer class above and look into this Lock implementation you will notice that threads are now blocked trying to access the lock() method, if more than one thread calls lock() simultanously. Second, if the lock is locked, the threads are blocked in the wait() call inside the while(isLocked) loop in the lock() method. Remember that a thread calling wait() releases the synchronization lock on the Lock instance, so threads waiting to enter lock() can now do so. The result is that multiple threads can end up having called wait() inside lock(). + +If you look back at the doSynchronized() method you will notice that the comment between lock() and unlock() states, that the code in between these two calls take a "long" time to execute. Let us further assume that this code takes long time to execute compared to entering the lock() method and calling wait() because the lock is locked. This means that the majority of the time waited to be able to lock the lock and enter the critical section is spent waiting in the wait() call inside the lock() method, not being blocked trying to enter the lock() method. + +As stated earlier synchronized blocks makes no guarantees about what thread is being granted access if more than one thread is waiting to enter. Nor does wait() make any guarantees about what thread is awakened when notify() is called. So, the current version of the Lock class makes no different guarantees with respect to fairness than synchronized version of doSynchronized(). But we can change that. + +The current version of the Lock class calls its own wait() method. If instead each thread calls wait() on a separate object, so that only one thread has called wait() on each object, the Lock class can decide which of these objects to call notify() on, thereby effectively selecting exactly what thread to awaken. + +A Fair Lock + +Below is shown the previous Lock class turned into a fair lock called FairLock. You will notice that the implementation has changed a bit with respect to synchronization and wait() / notify() compared to the Lock class shown earlier. + +Exactly how I arrived at this design beginning from the previous Lock class is a longer story involving several incremental design steps, each fixing the problem of the previous step: Nested Monitor Lockout, Slipped Conditions, and Missed Signals. That discussion is left out of this text to keep the text short, but each of the steps are discussed in the appropriate texts on the topic ( see the links above). What is important is, that every thread calling lock() is now queued, and only the first thread in the queue is allowed to lock the FairLock instance, if it is unlocked. All other threads are parked waiting until they reach the top of the queue. + +public class FairLock { + private boolean isLocked = false; + private Thread lockingThread = null; + private List waitingThreads = + new ArrayList (); + + public void lock() throws InterruptedException{ + QueueObject queueObject = new QueueObject(); + boolean isLockedForThisThread = true; + synchronized(this){ + waitingThreads.add(queueObject); + } + + while(isLockedForThisThread){ + synchronized(this){ + isLockedForThisThread = + isLocked || waitingThreads.get(0) != queueObject; + if(!isLockedForThisThread){ + isLocked = true; + waitingThreads.remove(queueObject); + lockingThread = Thread.currentThread(); + return; + } + } + try{ + queueObject.doWait(); + }catch(InterruptedException e){ + synchronized(this) { waitingThreads.remove(queueObject); } + throw e; + } + } + } + + public synchronized void unlock(){ + if(this.lockingThread != Thread.currentThread()){ + throw new IllegalMonitorStateException( + "Calling thread has not locked this lock"); + } + isLocked = false; + lockingThread = null; + if(waitingThreads.size() > 0){ + waitingThreads.get(0).doNotify(); + } + } +} +public class QueueObject { + + private boolean isNotified = false; + + public synchronized void doWait() throws InterruptedException { + while(!isNotified){ + this.wait(); + } + this.isNotified = false; + } + + public synchronized void doNotify() { + this.isNotified = true; + this.notify(); + } + + public boolean equals(Object o) { + return this == o; + } +} +First you might notice that the lock() method is no longer declared synchronized. Instead only the blocks necessary to synchronize are nested inside synchronized blocks. + +FairLock creates a new instance of QueueObject and enqueue it for each thread calling lock(). The thread calling unlock() will take the top QueueObject in the queue and call doNotify() on it, to awaken the thread waiting on that object. This way only one waiting thread is awakened at a time, rather than all waiting threads. This part is what governs the fairness of the FairLock. + +Notice how the state of the lock is still tested and set within the same synchronized block to avoid slipped conditions. + +Also notice that the QueueObject is really a semaphore. The doWait() and doNotify() methods store the signal internally in the QueueObject. This is done to avoid missed signals caused by a thread being preempted just before calling queueObject.doWait(), by another thread which calls unlock() and thereby queueObject.doNotify(). The queueObject.doWait() call is placed outside the synchronized(this) block to avoid nested monitor lockout, so another thread can actually call unlock() when no thread is executing inside the synchronized(this) block in lock() method. + +Finally, notice how the queueObject.doWait() is called inside a try - catch block. In case an InterruptedException is thrown the thread leaves the lock() method, and we need to dequeue it. + +A Note on Performance + +If you compare the Lock and FairLock classes you will notice that there is somewhat more going on inside the lock() and unlock() in the FairLock class. This extra code will cause the FairLock to be a sligtly slower synchronization mechanism than Lock. How much impact this will have on your application depends on how long time the code in the critical section guarded by the FairLock takes to execute. The longer this takes to execute, the less significant the added overhead of the synchronizer is. It does of course also depend on how often this code is called. \ No newline at end of file From 0b858ba5549a88cdb7e5c7ecc25008ceb55cc40a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 02:15:53 +0800 Subject: [PATCH 181/524] Published with https://stackedit.io/ --- ...41\347\250\213\351\224\201\346\255\273.md" | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 "Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" diff --git "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" new file mode 100644 index 0000000..872a216 --- /dev/null +++ "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" @@ -0,0 +1,131 @@ +#13.嵌套管程锁死(Nested Monitor Lockout) + +How Nested Monitor Lockout Occurs + +Nested monitor lockout is a problem similar to deadlock. A nested monitor lockout occurs like this: + +Thread 1 synchronizes on A +Thread 1 synchronizes on B (while synchronized on A) +Thread 1 decides to wait for a signal from another thread before continuing +Thread 1 calls B.wait() thereby releasing the lock on B, but not A. + +Thread 2 needs to lock both A and B (in that sequence) + to send Thread 1 the signal. +Thread 2 cannot lock A, since Thread 1 still holds the lock on A. +Thread 2 remain blocked indefinately waiting for Thread1 + to release the lock on A + +Thread 1 remain blocked indefinately waiting for the signal from + Thread 2, thereby + never releasing the lock on A, that must be released to make + it possible for Thread 2 to send the signal to Thread 1, etc. +This may sound like a pretty theoretical situation, but look at the naive Lock implemenation below: + +//lock implementation with nested monitor lockout problem + +public class Lock{ + protected MonitorObject monitorObject = new MonitorObject(); + protected boolean isLocked = false; + + public void lock() throws InterruptedException{ + synchronized(this){ + while(isLocked){ + synchronized(this.monitorObject){ + this.monitorObject.wait(); + } + } + isLocked = true; + } + } + + public void unlock(){ + synchronized(this){ + this.isLocked = false; + synchronized(this.monitorObject){ + this.monitorObject.notify(); + } + } + } +} +Notice how the lock() method first synchronizes on "this", then synchronizes on the monitorObject member. If isLocked is false there is no problem. The thread does not call monitorObject.wait(). If isLocked is true however, the thread calling lock() is parked waiting in the monitorObject.wait() call. + +The problem with this is, that the call to monitorObject.wait() only releases the synchronization monitor on the monitorObject member, and not the synchronization monitor associated with "this". In other words, the thread that was just parked waiting is still holding the synchronization lock on "this". + +When the thread that locked the Lock in the first place tries to unlock it by calling unlock() it will be blocked trying to enter the synchronized(this) block in the unlock() method. It will remain blocked until the thread waiting in lock() leaves the synchronized(this) block. But the thread waiting in the lock() method will not leave that block until the isLocked is set to false, and a monitorObject.notify() is executed, as it happens in unlock(). + +Put shortly, the thread waiting in lock() needs an unlock() call to execute successfully for it to exit lock() and the synchronized blocks inside it. But, no thread can actually execute unlock() until the thread waiting in lock() leaves the outer synchronized block. + +This result is that any thread calling either lock() or unlock() will become blocked indefinately. This is called a nested monitor lockout. + +A More Realistic Example + +You may claim that you would never implement a lock like the one shown earlier. That you would not call wait() and notify() on an internal monitor object, but rather on the This is probably true. But there are situations in which designs like the one above may arise. For instance, if you were to implement fairness in a Lock. When doing so you want each thread to call wait() on each their own queue object, so that you can notify the threads one at a time. + +Look at this naive implementation of a fair lock: + +//Fair Lock implementation with nested monitor lockout problem + +public class FairLock { + private boolean isLocked = false; + private Thread lockingThread = null; + private List waitingThreads = + new ArrayList (); + + public void lock() throws InterruptedException{ + QueueObject queueObject = new QueueObject(); + + synchronized(this){ + waitingThreads.add(queueObject); + + while(isLocked || waitingThreads.get(0) != queueObject){ + + synchronized(queueObject){ + try{ + queueObject.wait(); + }catch(InterruptedException e){ + waitingThreads.remove(queueObject); + throw e; + } + } + } + waitingThreads.remove(queueObject); + isLocked = true; + lockingThread = Thread.currentThread(); + } + } + + public synchronized void unlock(){ + if(this.lockingThread != Thread.currentThread()){ + throw new IllegalMonitorStateException( + "Calling thread has not locked this lock"); + } + isLocked = false; + lockingThread = null; + if(waitingThreads.size() > 0){ + QueueObject queueObject = waitingThread.get(0); + synchronized(queueObject){ + queueObject.notify(); + } + } + } +} +public class QueueObject {} +At first glance this implementation may look fine, but notice how the lock() method calls queueObject.wait(); from inside two synchronized blocks. One synchronized on "this", and nested inside that, a block synchronized on the queueObject local variable. When a thread calls queueObject.wait()it releases the lock on the QueueObject instance, but not the lock associated with "this". + +Notice too, that the unlock() method is declared synchronized which equals a synchronized(this) block. This means, that if a thread is waiting inside lock() the monitor object associated with "this" will be locked by the waiting thread. All threads calling unlock() will remain blocked indefinately, waiting for the waiting thread to release the lock on "this". But this will never happen, since this only happens if a thread succeeds in sending a signal to the waiting thread, and this can only be sent by executing the unlock() method. + +And so, the FairLock implementation from above could lead to nested monitor lockout. A better implementation of a fair lock is described in the text Starvation and Fairness. + +Nested Monitor Lockout vs. Deadlock + +The result of nested monitor lockout and deadlock are pretty much the same: The threads involved end up blocked forever waiting for each other. + +The two situations are not equal though. As explained in the text on Deadlock a deadlock occurs when two threads obtain locks in different order. Thread 1 locks A, waits for B. Thread 2 has locked B, and now waits for A. As explained in the text on Deadlock Prevention deadlocks can be avoided by always locking the locks in the same order (Lock Ordering). However, a nested monitor lockout occurs exactly by two threads taking the locks in the same order. Thread 1 locks A and B, then releases B and waits for a signal from Thread 2. Thread 2 needs both A and B to send Thread 1 the signal. So, one thread is waiting for a signal, and another for a lock to be released. + +The difference is summed up here: + +In deadlock, two threads are waiting for each other to release locks. + +In nested monitor lockout, Thread 1 is holding a lock A, and waits +for a signal from Thread 2. Thread 2 needs the lock A to send the +signal to Thread 1. From e4a6ee2efad145bf0da2f28828b33e4f2db4a013 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 02:18:40 +0800 Subject: [PATCH 182/524] Published with https://stackedit.io/ --- Java-Concurrency/14.Slipped Conditions.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Java-Concurrency/14.Slipped Conditions.md diff --git a/Java-Concurrency/14.Slipped Conditions.md b/Java-Concurrency/14.Slipped Conditions.md new file mode 100644 index 0000000..6746204 --- /dev/null +++ b/Java-Concurrency/14.Slipped Conditions.md @@ -0,0 +1,4 @@ +#14.Slipped Conditions + + +> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file From 4d8b21bbee9db496df56767ddd4428bc9c18c734 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 02:18:59 +0800 Subject: [PATCH 183/524] Published with https://stackedit.io/ --- Java-Concurrency/14.Slipped Conditions.md | 227 +++++++++++++++++++++- 1 file changed, 226 insertions(+), 1 deletion(-) diff --git a/Java-Concurrency/14.Slipped Conditions.md b/Java-Concurrency/14.Slipped Conditions.md index 6746204..4af0ffb 100644 --- a/Java-Concurrency/14.Slipped Conditions.md +++ b/Java-Concurrency/14.Slipped Conditions.md @@ -1,4 +1,229 @@ #14.Slipped Conditions +What is Slipped Conditions? -> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file +Slipped conditions means, that from the time a thread has checked a certain condition until it acts upon it, the condition has been changed by another thread so that it is errornous for the first thread to act. Here is a simple example: + +public class Lock { + + private boolean isLocked = true; + + public void lock(){ + synchronized(this){ + while(isLocked){ + try{ + this.wait(); + } catch(InterruptedException e){ + //do nothing, keep waiting + } + } + } + + synchronized(this){ + isLocked = true; + } + } + + public synchronized void unlock(){ + isLocked = false; + this.notify(); + } + +} +Notice how the lock() method contains two synchronized blocks. The first block waits until isLocked is false. The second block sets isLocked to true, to lock the Lock instance for other threads. + +Imagine that isLocked is false, and two threads call lock() at the same time. If the first thread entering the first synchronized block is preempted right after the first synchronized block, this thread will have checked isLocked and noted it to be false. If the second thread is now allowed to execute, and thus enter the first synchronized block, this thread too will see isLocked as false. Now both threads have read the condition as false. Then both threads will enter the second synchronized block, set isLocked to true, and continue. + +This situation is an example of slipped conditions. Both threads test the condition, then exit the synchronized block, thereby allowing other threads to test the condition, before any of the two first threads change the conditions for subsequent threads. In other words, the condition has slipped from the time the condition was checked until the threads change it for subsequent threads. + +To avoid slipped conditions the testing and setting of the conditions must be done atomically by the thread doing it, meaning that no other thread can check the condition in between the testing and setting of the condition by the first thread. + +The solution in the example above is simple. Just move the line isLocked = true; up into the first synchronized block, right after the while loop. Here is how it looks: + +public class Lock { + + private boolean isLocked = true; + + public void lock(){ + synchronized(this){ + while(isLocked){ + try{ + this.wait(); + } catch(InterruptedException e){ + //do nothing, keep waiting + } + } + isLocked = true; + } + } + + public synchronized void unlock(){ + isLocked = false; + this.notify(); + } + +} +Now the testing and setting of the isLocked condition is done atomically from inside the same synchronized block. + +A More Realistic Example + +You may rightfully argue that you would never implement a Lock like the first implementation shown in this text, and thus claim slipped conditions to be a rather theoretical problem. But the first example was kept rather simple to better convey the notion of slipped conditions. + +A more realistic example would be during the implementation of a fair lock, as discussed in the text on Starvation and Fairness. If we look at the naive implementation from the text Nested Monitor Lockout, and try to remove the nested monitor lock problem it, it is easy to arrive at an implementation that suffers from slipped conditions. First I'll show the example from the nested monitor lockout text: + +//Fair Lock implementation with nested monitor lockout problem + +public class FairLock { + private boolean isLocked = false; + private Thread lockingThread = null; + private List waitingThreads = + new ArrayList (); + + public void lock() throws InterruptedException{ + QueueObject queueObject = new QueueObject(); + + synchronized(this){ + waitingThreads.add(queueObject); + + while(isLocked || waitingThreads.get(0) != queueObject){ + + synchronized(queueObject){ + try{ + queueObject.wait(); + }catch(InterruptedException e){ + waitingThreads.remove(queueObject); + throw e; + } + } + } + waitingThreads.remove(queueObject); + isLocked = true; + lockingThread = Thread.currentThread(); + } + } + + public synchronized void unlock(){ + if(this.lockingThread != Thread.currentThread()){ + throw new IllegalMonitorStateException( + "Calling thread has not locked this lock"); + } + isLocked = false; + lockingThread = null; + if(waitingThreads.size() > 0){ + QueueObject queueObject = waitingThread.get(0); + synchronized(queueObject){ + queueObject.notify(); + } + } + } +} +public class QueueObject {} +Notice how the synchronized(queueObject) with its queueObject.wait() call is nested inside the synchronized(this) block, resulting in the nested monitor lockout problem. To avoid this problem the synchronized(queueObject) block must be moved outside the synchronized(this) block. Here is how that could look: + +//Fair Lock implementation with slipped conditions problem + +public class FairLock { + private boolean isLocked = false; + private Thread lockingThread = null; + private List waitingThreads = + new ArrayList (); + + public void lock() throws InterruptedException{ + QueueObject queueObject = new QueueObject(); + + synchronized(this){ + waitingThreads.add(queueObject); + } + + boolean mustWait = true; + while(mustWait){ + + synchronized(this){ + mustWait = isLocked || waitingThreads.get(0) != queueObject; + } + + synchronized(queueObject){ + if(mustWait){ + try{ + queueObject.wait(); + }catch(InterruptedException e){ + waitingThreads.remove(queueObject); + throw e; + } + } + } + } + + synchronized(this){ + waitingThreads.remove(queueObject); + isLocked = true; + lockingThread = Thread.currentThread(); + } + } +} +Note: Only the lock() method is shown, since it is the only method I have changed. + +Notice how the lock() method now contains 3 synchronized blocks. + +The first synchronized(this) block checks the condition by setting mustWait = isLocked || waitingThreads.get(0) != queueObject. + +The second synchronized(queueObject) block checks if the thread is to wait or not. Already at this time another thread may have unlocked the lock, but lets forget that for the time being. Let's assume that the lock was unlocked, so the thread exits the synchronized(queueObject) block right away. + +The third synchronized(this) block is only executed if mustWait = false. This sets the condition isLocked back to true etc. and leaves the lock() method. + +Imagine what will happen if two threads call lock() at the same time when the lock is unlocked. First thread 1 will check the isLocked conditition and see it false. Then thread 2 will do the same thing. Then neither of them will wait, and both will set the state isLocked to true. This is a prime example of slipped conditions. + +Removing the Slipped Conditions Problem + +To remove the slipped conditions problem from the example above, the content of the last synchronized(this) block must be moved up into the first block. The code will naturally have to be changed a little bit too, to adapt to this move. Here is how it looks: + +//Fair Lock implementation without nested monitor lockout problem, +//but with missed signals problem. + +public class FairLock { + private boolean isLocked = false; + private Thread lockingThread = null; + private List waitingThreads = + new ArrayList (); + + public void lock() throws InterruptedException{ + QueueObject queueObject = new QueueObject(); + + synchronized(this){ + waitingThreads.add(queueObject); + } + + boolean mustWait = true; + while(mustWait){ + + + synchronized(this){ + mustWait = isLocked || waitingThreads.get(0) != queueObject; + if(!mustWait){ + waitingThreads.remove(queueObject); + isLocked = true; + lockingThread = Thread.currentThread(); + return; + } + } + + synchronized(queueObject){ + if(mustWait){ + try{ + queueObject.wait(); + }catch(InterruptedException e){ + waitingThreads.remove(queueObject); + throw e; + } + } + } + } + } +} +Notice how the local variable mustWait is tested and set within the same synchronized code block now. Also notice, that even if the mustWait local variable is also checked outside the synchronized(this) code block, in the while(mustWait) clause, the value of the mustWait variable is never changed outside the synchronized(this). A thread that evaluates mustWait to false will atomically also set the internal conditions (isLocked) so that any other thread checking the condition will evaluate it to true. + +The return; statement in the synchronized(this) block is not necessary. It is just a small optimization. If the thread must not wait (mustWait == false), then there is no reason to enter the synchronized(queueObject) block and execute the if(mustWait) clause. + +The observant reader will notice that the above implementation of a fair lock still suffers from a missed signal problem. Imagine that the FairLock instance is locked when a thread calls lock(). After the first synchronized(this) block mustWait is true. Then imagine that the thread calling lock() is preempted, and the thread that locked the lock calls unlock(). If you look at the unlock() implementation shown earlier, you will notice that it calls queueObject.notify(). But, since the thread waiting in lock() has not yet called queueObject.wait(), the call to queueObject.notify() passes into oblivion. The signal is missed. When the thread calling lock() right after calls queueObject.wait() it will remain blocked until some other thread calls unlock(), which may never happen. + +The missed signals problems is the reason that the FairLock implementation shown in the text Starvation and Fairness has turned the QueueObject class into a semaphore with two methods: doWait() and doNotify(). These methods store and react the signal internally in the QueueObject. That way the signal is not missed, even if doNotify() is called before doWait(). \ No newline at end of file From 15382b043b2d9b5243f22c140c14ad12b62d0949 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 02:20:22 +0800 Subject: [PATCH 184/524] Published with https://stackedit.io/ --- ...va\344\270\255\347\232\204\351\224\201.md" | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 "Java-Concurrency/15Java\344\270\255\347\232\204\351\224\201.md" diff --git "a/Java-Concurrency/15Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15Java\344\270\255\347\232\204\351\224\201.md" new file mode 100644 index 0000000..0cbb74a --- /dev/null +++ "b/Java-Concurrency/15Java\344\270\255\347\232\204\351\224\201.md" @@ -0,0 +1,169 @@ +#Java中的锁 + +A lock is a thread synchronization mechanism like synchronized blocks except locks can be more sophisticated than Java's synchronized blocks. Locks (and other more advanced synchronization mechanisms) are created using synchronized blocks, so it is not like we can get totally rid of the synchronized keyword. + +From Java 5 the package java.util.concurrent.locks contains several lock implementations, so you may not have to implement your own locks. But you will still need to know how to use them, and it can still be useful to know the theory behind their implementation. For more details, see my tutorial on the java.util.concurrent.locks.Lock interface. + +A Simple Lock + +Let's start out by looking at a synchronized block of Java code: + +public class Counter{ + + private int count = 0; + + public int inc(){ + synchronized(this){ + return ++count; + } + } +} +Notice the synchronized(this) block in the inc() method. This block makes sure that only one thread can execute the return ++count at a time. The code in the synchronized block could have been more advanced, but the simple ++count suffices to get the point across. + +The Counter class could have been written like this instead, using a Lock instead of a synchronized block: + +public class Counter{ + + private Lock lock = new Lock(); + private int count = 0; + + public int inc(){ + lock.lock(); + int newCount = ++count; + lock.unlock(); + return newCount; + } +} +The lock() method locks the Lock instance so that all threads calling lock() are blocked until unlock() is executed. + +Here is a simple Lock implementation: + +public class Lock{ + + private boolean isLocked = false; + + public synchronized void lock() + throws InterruptedException{ + while(isLocked){ + wait(); + } + isLocked = true; + } + + public synchronized void unlock(){ + isLocked = false; + notify(); + } +} +Notice the while(isLocked) loop, which is also called a "spin lock". Spin locks and the methods wait() and notify() are covered in more detail in the text Thread Signaling. While isLocked is true, the thread calling lock() is parked waiting in the wait() call. In case the thread should return unexpectedly from the wait() call without having received a notify() call (AKA a Spurious Wakeup) the thread re-checks the isLocked condition to see if it is safe to proceed or not, rather than just assume that being awakened means it is safe to proceed. If isLocked is false, the thread exits the while(isLocked) loop, and sets isLocked back to true, to lock the Lock instance for other threads calling lock(). + +When the thread is done with the code in the critical section (the code between lock() and unlock()), the thread calls unlock(). Executing unlock() sets isLocked back to false, and notifies (awakens) one of the threads waiting in the wait() call in the lock() method, if any. + +Lock Reentrance + +Synchronized blocks in Java are reentrant. This means, that if a Java thread enters a synchronized block of code, and thereby take the lock on the monitor object the block is synchronized on, the thread can enter other Java code blocks synchronized on the same monitor object. Here is an example: + +public class Reentrant{ + + public synchronized outer(){ + inner(); + } + + public synchronized inner(){ + //do something + } +} +Notice how both outer() and inner() are declared synchronized, which in Java is equivalent to a synchronized(this) block. If a thread calls outer() there is no problem calling inner() from inside outer(), since both methods (or blocks) are synchronized on the same monitor object ("this"). If a thread already holds the lock on a monitor object, it has access to all blocks synchronized on the same monitor object. This is called reentrance. The thread can reenter any block of code for which it already holds the lock. + +The lock implementation shown earlier is not reentrant. If we rewrite the Reentrant class like below, the thread calling outer() will be blocked inside the lock.lock() in the inner() method. + +public class Reentrant2{ + + Lock lock = new Lock(); + + public outer(){ + lock.lock(); + inner(); + lock.unlock(); + } + + public synchronized inner(){ + lock.lock(); + //do something + lock.unlock(); + } +} +A thread calling outer() will first lock the Lock instance. Then it will call inner(). Inside the inner() method the thread will again try to lock the Lock instance. This will fail (meaning the thread will be blocked), since the Lock instance was locked already in the outer() method. + +The reason the thread will be blocked the second time it calls lock() without having called unlock() in between, is apparent when we look at the lock() implementation: + +public class Lock{ + + boolean isLocked = false; + + public synchronized void lock() + throws InterruptedException{ + while(isLocked){ + wait(); + } + isLocked = true; + } + + ... +} +It is the condition inside the while loop (spin lock) that determines if a thread is allowed to exit the lock() method or not. Currently the condition is that isLocked must be false for this to be allowed, regardless of what thread locked it. + +To make the Lock class reentrant we need to make a small change: + +public class Lock{ + + boolean isLocked = false; + Thread lockedBy = null; + int lockedCount = 0; + + public synchronized void lock() + throws InterruptedException{ + Thread callingThread = Thread.currentThread(); + while(isLocked && lockedBy != callingThread){ + wait(); + } + isLocked = true; + lockedCount++; + lockedBy = callingThread; + } + + + public synchronized void unlock(){ + if(Thread.curentThread() == this.lockedBy){ + lockedCount--; + + if(lockedCount == 0){ + isLocked = false; + notify(); + } + } + } + + ... +} +Notice how the while loop (spin lock) now also takes the thread that locked the Lock instance into consideration. If either the lock is unlocked (isLocked = false) or the calling thread is the thread that locked the Lock instance, the while loop will not execute, and the thread calling lock() will be allowed to exit the method. + +Additionally, we need to count the number of times the lock has been locked by the same thread. Otherwise, a single call to unlock() will unlock the lock, even if the lock has been locked multiple times. We don't want the lock to be unloced until the thread that locked it, has executed the same amount of unlock() calls as lock() calls. + +The Lock class is now reentrant. + +Lock Fairness + +Java's synchronized blocks makes no guarantees about the sequence in which threads trying to enter them are granted access. Therefore, if many threads are constantly competing for access to the same synchronized block, there is a risk that one or more of the threads are never granted access - that access is always granted to other threads. This is called starvation. To avoid this a Lock should be fair. Since the Lock implementations shown in this text uses synchronized blocks internally, they do not guarantee fairness. Starvation and fairness are discussed in more detail in the text Starvation and Fairness. + +Calling unlock() From a finally-clause + +When guarding a critical section with a Lock, and the critical section may throw exceptions, it is important to call the unlock() method from inside a finally-clause. Doing so makes sure that the Lock is unlocked so other threads can lock it. Here is an example: + +lock.lock(); +try{ + //do critical section code, which may throw exception +} finally { + lock.unlock(); +} +This little construct makes sure that the Lock is unlocked in case an exception is thrown from the code in the critical section. If unlock() was not called from inside a finally-clause, and an exception was thrown from the critical section, the Lock would remain locked forever, causing all threads calling lock() on that Lock instance to halt indefinately. \ No newline at end of file From fc3e7ceeac6eebe62b0de969e6f7c0c78ba939e7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 11:20:59 +0800 Subject: [PATCH 185/524] Published with https://stackedit.io/ --- ...51\245\277\345\222\214\345\205\254\345\271\263.md" | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index f0f7c53..140e4e4 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -1,6 +1,9 @@ #饥饿和公平(Starvation and Fairness) -If a thread is not granted CPU time because other threads grab it all, it is called "starvation". The thread is "starved to death" because other threads are allowed the CPU time instead of it. The solution to starvation is called "fairness" - that all threads are fairly granted a chance to execute. +如果一个线程由于CPU时间全部被其他线程抢占而得不到CPU时间,这就称为**饥饿(Starvation)**。这个线程因为得不到CPU机会而“饿死(starved to death)"。解决饥饿的方案称为**公平(Fairness)**--所有的线程都能公平地获得CPU时间。 + +##Java中产生饥饿的原因 + Causes of Starvation in Java @@ -23,7 +26,7 @@ Threads waiting on an object (called wait() on it) remain waiting indefinitely The notify() method makes no guarantee about what thread is awakened if multiple thread have called wait() on the object notify() is called on. It could be any of the threads waiting. Therefore there is a risk that a thread waiting on a certain object is never awakened because other waiting threads are always awakened instead of it. -Implementing Fairness in Java +##Implementing Fairness in Java While it is not possible to implement 100% fairness in Java we can still implement our synchronization constructs to increase fairness between threads. @@ -86,7 +89,7 @@ As stated earlier synchronized blocks makes no guarantees about what thread is b The current version of the Lock class calls its own wait() method. If instead each thread calls wait() on a separate object, so that only one thread has called wait() on each object, the Lock class can decide which of these objects to call notify() on, thereby effectively selecting exactly what thread to awaken. -A Fair Lock +##A Fair Lock Below is shown the previous Lock class turned into a fair lock called FairLock. You will notice that the implementation has changed a bit with respect to synchronization and wait() / notify() compared to the Lock class shown earlier. @@ -167,6 +170,6 @@ Also notice that the QueueObject is really a semaphore. The doWait() and doNotif Finally, notice how the queueObject.doWait() is called inside a try - catch block. In case an InterruptedException is thrown the thread leaves the lock() method, and we need to dequeue it. -A Note on Performance +##A Note on Performance If you compare the Lock and FairLock classes you will notice that there is somewhat more going on inside the lock() and unlock() in the FairLock class. This extra code will cause the FairLock to be a sligtly slower synchronization mechanism than Lock. How much impact this will have on your application depends on how long time the code in the critical section guarded by the FairLock takes to execute. The longer this takes to execute, the less significant the added overhead of the synchronizer is. It does of course also depend on how often this code is called. \ No newline at end of file From 7e7e2c9784c95ebf396409607ca02b69e8c74e65 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 11:43:29 +0800 Subject: [PATCH 186/524] Published with https://stackedit.io/ --- ...77\345\222\214\345\205\254\345\271\263.md" | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index 140e4e4..f29127b 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -4,25 +4,21 @@ ##Java中产生饥饿的原因 +在Java中,下面三种常见原因会导致饥饿: -Causes of Starvation in Java +* 高优先级的线程抢占了所有的CPU时间。 +* 线程陷入无止境地等待进入同步块状态,因为其他线程总是能够在它之前获得进入同步块的机会。 +* 线程陷入无止境地等待被唤醒(调用了对象的wait()方法)状态,因为其他线程总能够持续获得唤醒机会而不是这个线程。 -The following three common causes can lead to starvation of threads in Java: +###高优先级线程抢占了所有的CPU时间 -Threads with high priority swallow all CPU time from threads with lower priority. +你可以为每个线程设置优先级。高优先级的线程能够获得更多的CPU时间。优先级可以设置为1-10之间。这些优先级值的解释根据操作系统的差异而有所不同。对于大部分应用程式来说,你最好不要改变其优先级值。 -Threads are blocked indefinately waiting to enter a synchronized block, because other threads are constantly allowed access before it. - -Threads waiting on an object (called wait() on it) remain waiting indefinitely because other threads are constantly awakened instead of it. -Threads with high priority swallow all CPU time from threads with lower priority - -You can set the thread priority of each thread individually. The higher the priority the more CPU time the thread is granted. You can set the priority of threads between 1 and 10. Exactly how this is interpreted depends on the operating system your application is running on. For most applications you are better off leaving the priority unchanged. - -Threads are blocked indefinitely waiting to enter a synchronized block +###Threads are blocked indefinitely waiting to enter a synchronized block Java's synchronized code blocks can be another cause of starvation. Java's synchronized code block makes no guarantee about the sequence in which threads waiting to enter the synchronized block are allowed to enter. This means that there is a theoretical risk that a thread remains blocked forever trying to enter the block, because other threads are constantly granted access before it. This problem is called "starvation", that a thread is "starved to death" by because other threads are allowed the CPU time instead of it. -Threads waiting on an object (called wait() on it) remain waiting indefinitely +###Threads waiting on an object (called wait() on it) remain waiting indefinitely The notify() method makes no guarantee about what thread is awakened if multiple thread have called wait() on the object notify() is called on. It could be any of the threads waiting. Therefore there is a risk that a thread waiting on a certain object is never awakened because other waiting threads are always awakened instead of it. From 23480fb0cd5f08342971ac08e456d0fc59a7b8b9 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 11:45:44 +0800 Subject: [PATCH 187/524] Published with https://stackedit.io/ --- ...351\245\277\345\222\214\345\205\254\345\271\263.md" | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index f29127b..b7b8302 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -14,15 +14,15 @@ 你可以为每个线程设置优先级。高优先级的线程能够获得更多的CPU时间。优先级可以设置为1-10之间。这些优先级值的解释根据操作系统的差异而有所不同。对于大部分应用程式来说,你最好不要改变其优先级值。 -###Threads are blocked indefinitely waiting to enter a synchronized block +###线程陷入无止境地等待进入同步块状态 Java's synchronized code blocks can be another cause of starvation. Java's synchronized code block makes no guarantee about the sequence in which threads waiting to enter the synchronized block are allowed to enter. This means that there is a theoretical risk that a thread remains blocked forever trying to enter the block, because other threads are constantly granted access before it. This problem is called "starvation", that a thread is "starved to death" by because other threads are allowed the CPU time instead of it. -###Threads waiting on an object (called wait() on it) remain waiting indefinitely +### 线程陷入无止境地等待被唤醒(调用了对象的wait()方法)状态, The notify() method makes no guarantee about what thread is awakened if multiple thread have called wait() on the object notify() is called on. It could be any of the threads waiting. Therefore there is a risk that a thread waiting on a certain object is never awakened because other waiting threads are always awakened instead of it. -##Implementing Fairness in Java +##在Java中的公平性实现(Implementing Fairness in Java) While it is not possible to implement 100% fairness in Java we can still implement our synchronization constructs to increase fairness between threads. @@ -85,7 +85,7 @@ As stated earlier synchronized blocks makes no guarantees about what thread is b The current version of the Lock class calls its own wait() method. If instead each thread calls wait() on a separate object, so that only one thread has called wait() on each object, the Lock class can decide which of these objects to call notify() on, thereby effectively selecting exactly what thread to awaken. -##A Fair Lock +##公平锁(A Fair Lock) Below is shown the previous Lock class turned into a fair lock called FairLock. You will notice that the implementation has changed a bit with respect to synchronization and wait() / notify() compared to the Lock class shown earlier. @@ -166,6 +166,6 @@ Also notice that the QueueObject is really a semaphore. The doWait() and doNotif Finally, notice how the queueObject.doWait() is called inside a try - catch block. In case an InterruptedException is thrown the thread leaves the lock() method, and we need to dequeue it. -##A Note on Performance +##性能(A Note on Performance) If you compare the Lock and FairLock classes you will notice that there is somewhat more going on inside the lock() and unlock() in the FairLock class. This extra code will cause the FairLock to be a sligtly slower synchronization mechanism than Lock. How much impact this will have on your application depends on how long time the code in the critical section guarded by the FairLock takes to execute. The longer this takes to execute, the less significant the added overhead of the synchronizer is. It does of course also depend on how often this code is called. \ No newline at end of file From 15c41b016915c9ef7b7c10163734fa636a295355 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 12:01:26 +0800 Subject: [PATCH 188/524] Published with https://stackedit.io/ --- ...\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index b7b8302..30340ac 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -20,7 +20,7 @@ Java's synchronized code blocks can be another cause of starvation. Java's synch ### 线程陷入无止境地等待被唤醒(调用了对象的wait()方法)状态, -The notify() method makes no guarantee about what thread is awakened if multiple thread have called wait() on the object notify() is called on. It could be any of the threads waiting. Therefore there is a risk that a thread waiting on a certain object is never awakened because other waiting threads are always awakened instead of it. +如果多个线程都调用了同一个对象的`wait()`方法而,当一个线程调用这个对象的`notify()`方法后,并不能确定哪个调用了`wait()`方法的线程能够被唤醒。它可以是这些线程的任意一个。如果一个线程由于唤醒机会被其他线程抢占而一直无法被唤醒,这是非常危险的。 ##在Java中的公平性实现(Implementing Fairness in Java) From c7bcbc98421c36db7bf5aad52b8c7d13458a6ef6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 12:12:11 +0800 Subject: [PATCH 189/524] Published with https://stackedit.io/ --- ...\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index 30340ac..da3f168 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -16,7 +16,7 @@ ###线程陷入无止境地等待进入同步块状态 -Java's synchronized code blocks can be another cause of starvation. Java's synchronized code block makes no guarantee about the sequence in which threads waiting to enter the synchronized block are allowed to enter. This means that there is a theoretical risk that a thread remains blocked forever trying to enter the block, because other threads are constantly granted access before it. This problem is called "starvation", that a thread is "starved to death" by because other threads are allowed the CPU time instead of it. +Java同步代码块是另一个能够导致饥饿的原因。Java同步代码块不能够保证进入同步块线程的顺序。这意味着,理论上存在可以陷入无限等待进入同步块的线程。线程会因为得不到任何CPU机会而饿死。 ### 线程陷入无止境地等待被唤醒(调用了对象的wait()方法)状态, From a246b78ed72f61bc3d89fc3554d877ea6b2db18f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 12:20:14 +0800 Subject: [PATCH 190/524] Published with https://stackedit.io/ --- ...\245\277\345\222\214\345\205\254\345\271\263.md" | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index da3f168..0038054 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -24,10 +24,11 @@ Java同步代码块是另一个能够导致饥饿的原因。Java同步代码块 ##在Java中的公平性实现(Implementing Fairness in Java) -While it is not possible to implement 100% fairness in Java we can still implement our synchronization constructs to increase fairness between threads. +虽然在Java中实现100%的公平是不可能,但是我们仍然能够通过同步结构提高线程的公平性。 -First lets study a simple synchronized code block: +我们学习一下同步代码块: +```Java public class Synchronizer{ public synchronized void doSynchronized(){ @@ -35,9 +36,13 @@ public class Synchronizer{ } } -If more than one thread call the doSynchronized() method, some of them will be blocked until the first thread granted access has left the method. If more than one thread are blocked waiting for access there is no guarantee about which thread is granted access next. +``` + +如果有多个线程调用`doSynchroinized()`方法,有一个线程会进入同步代码块,而剩余的则会阻塞直到第一个线程离开同步代码块。在多个线程阻塞的时候,我们并不知道哪个线程会成为下一个进入同步代码块的线程。 + +##使用Locks代替Synchronized块(Using Locks Instead of Synchronized Blocks) + -Using Locks Instead of Synchronized Blocks To increase the fairness of waiting threads first we will change the code block to be guarded by a lock rather than a synchronized block: From 5b0b27fba58f0ef412fa1abef3aa7696298f810d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 12:25:59 +0800 Subject: [PATCH 191/524] Published with https://stackedit.io/ --- ...245\277\345\222\214\345\205\254\345\271\263.md" | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index 0038054..d246be0 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -42,10 +42,9 @@ public class Synchronizer{ ##使用Locks代替Synchronized块(Using Locks Instead of Synchronized Blocks) +为了提高线程的公平性,我们可以使用Locks来代替Synchronized块: - -To increase the fairness of waiting threads first we will change the code block to be guarded by a lock rather than a synchronized block: - +```Java public class Synchronizer{ Lock lock = new Lock(); @@ -56,10 +55,13 @@ public class Synchronizer{ } } -Notice how the doSynchronized() method is no longer declared synchronized. Instead the critical section is guarded by the lock.lock() and lock.unlock() calls. +``` -A simple implementation of the Lock class could look like this: +注意这里并没有使用**synchronized** 关键字声明方法。取而代之,我们使用`lock.lock()`和`lock.unlock()`来包裹临界区。 +下面是一个Lock类的简单实现: + +```Java public class Lock{ private boolean isLocked = false; private Thread lockingThread = null; @@ -82,6 +84,8 @@ public class Lock{ notify(); } } +``` + If you look at the Synchronizer class above and look into this Lock implementation you will notice that threads are now blocked trying to access the lock() method, if more than one thread calls lock() simultanously. Second, if the lock is locked, the threads are blocked in the wait() call inside the while(isLocked) loop in the lock() method. Remember that a thread calling wait() releases the synchronization lock on the Lock instance, so threads waiting to enter lock() can now do so. The result is that multiple threads can end up having called wait() inside lock(). If you look back at the doSynchronized() method you will notice that the comment between lock() and unlock() states, that the code in between these two calls take a "long" time to execute. Let us further assume that this code takes long time to execute compared to entering the lock() method and calling wait() because the lock is locked. This means that the majority of the time waited to be able to lock the lock and enter the critical section is spent waiting in the wait() call inside the lock() method, not being blocked trying to enter the lock() method. From 71a8b5249fcbd956ef5cc57847f93bdbe3613e83 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 12:28:53 +0800 Subject: [PATCH 192/524] Published with https://stackedit.io/ From cf26d797405c7d4e4978363d8b6d9349931332af Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 12:40:54 +0800 Subject: [PATCH 193/524] Published with https://stackedit.io/ --- ...245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" | 3 +++ 1 file changed, 3 insertions(+) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index d246be0..be1d263 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -100,6 +100,7 @@ Below is shown the previous Lock class turned into a fair lock called FairLock. Exactly how I arrived at this design beginning from the previous Lock class is a longer story involving several incremental design steps, each fixing the problem of the previous step: Nested Monitor Lockout, Slipped Conditions, and Missed Signals. That discussion is left out of this text to keep the text short, but each of the steps are discussed in the appropriate texts on the topic ( see the links above). What is important is, that every thread calling lock() is now queued, and only the first thread in the queue is allowed to lock the FairLock instance, if it is unlocked. All other threads are parked waiting until they reach the top of the queue. +``` public class FairLock { private boolean isLocked = false; private Thread lockingThread = null; @@ -165,6 +166,8 @@ public class QueueObject { return this == o; } } +``` + First you might notice that the lock() method is no longer declared synchronized. Instead only the blocks necessary to synchronize are nested inside synchronized blocks. FairLock creates a new instance of QueueObject and enqueue it for each thread calling lock(). The thread calling unlock() will take the top QueueObject in the queue and call doNotify() on it, to awaken the thread waiting on that object. This way only one waiting thread is awakened at a time, rather than all waiting threads. This part is what governs the fairness of the FairLock. From 6e457b6d1a6b05016cb1efed3f8ae9995c7406e2 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 12:50:57 +0800 Subject: [PATCH 194/524] Published with https://stackedit.io/ From 73073683ad1cc554db10f40273c56dca4709390d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 13:19:36 +0800 Subject: [PATCH 195/524] Published with https://stackedit.io/ --- ...45\245\351\245\277\345\222\214\345\205\254\345\271\263.md" | 4 ++++ 1 file changed, 4 insertions(+) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index be1d263..1f55500 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -86,6 +86,10 @@ public class Lock{ } ``` +对比之前的Synchronizer类,当多个线程同时调用`lock()` 方法时,只有一个线程能够进入`lock()`方法,其余的会阻塞在`lock()`方法上。然后,如果isLocked的值为true,则该线程会进入while循环内部,调用`wait()`方法并释放当前对象的锁,阻塞在同步块的其中一个线程会进入同步块。结果就是,阻塞在`lock()`方法上的线程依次进入同步块并调用`wait()`方法。 + + + If you look at the Synchronizer class above and look into this Lock implementation you will notice that threads are now blocked trying to access the lock() method, if more than one thread calls lock() simultanously. Second, if the lock is locked, the threads are blocked in the wait() call inside the while(isLocked) loop in the lock() method. Remember that a thread calling wait() releases the synchronization lock on the Lock instance, so threads waiting to enter lock() can now do so. The result is that multiple threads can end up having called wait() inside lock(). If you look back at the doSynchronized() method you will notice that the comment between lock() and unlock() states, that the code in between these two calls take a "long" time to execute. Let us further assume that this code takes long time to execute compared to entering the lock() method and calling wait() because the lock is locked. This means that the majority of the time waited to be able to lock the lock and enter the critical section is spent waiting in the wait() call inside the lock() method, not being blocked trying to enter the lock() method. From 0f8944ac3944d730c75a2149b3158b11ecf2edb3 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sun, 14 Sep 2014 13:34:05 +0800 Subject: [PATCH 196/524] Published with https://stackedit.io/ --- ...\245\277\345\222\214\345\205\254\345\271\263.md" | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index 1f55500..f7feaf1 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -85,18 +85,19 @@ public class Lock{ } } ``` +看下Synchronizer类和lock类,当多个线程同时调用`lock()` 方法时,只有一个线程能够进入`lock()`方法,其余的会阻塞在`lock()`方法上。然后,如果isLocked的值为true,则该线程会进入while循环内部,调用`wait()`方法并释放当前对象的锁,阻塞在同步块的其中一个线程会进入同步块。结果就是,阻塞在`lock()`方法上的线程依次进入同步块并调用`wait()`方法。 -对比之前的Synchronizer类,当多个线程同时调用`lock()` 方法时,只有一个线程能够进入`lock()`方法,其余的会阻塞在`lock()`方法上。然后,如果isLocked的值为true,则该线程会进入while循环内部,调用`wait()`方法并释放当前对象的锁,阻塞在同步块的其中一个线程会进入同步块。结果就是,阻塞在`lock()`方法上的线程依次进入同步块并调用`wait()`方法。 +再看下Synchronized类的`doSynchronized()`方法,你会发现`lock()`方法与`unlock()`方法之间的注释,这之间的代码会执行相当长的一段时间。让我们假设这段代码相比进入`lock()`方法和调用`wait()`方法会执行相当长一段时间。这意味着大部分时间用在等待进入锁和进入临界区的过程是用在wait()的等待中,而不是被阻塞在试图进入lock()方法中。 +(If you look back at the doSynchronized() method you will notice that the comment between lock() and unlock() states, that the code in between these two calls take a "long" time to execute. Let us further assume that this code takes long time to execute compared to entering the lock() method and calling wait() because the lock is locked. This means that the majority of the time waited to be able to lock the lock and enter the critical section is spent waiting in the wait() call inside the lock() method, not being blocked trying to enter the lock() method.) +在早些时候提到过,同步块不会对等待进入的多个线程谁能获得访问做任何保障,同样当调用notify()时,wait()也不会做保障一定能唤醒线程(至于为什么,请看线程通信)。因此这个版本的Lock类和doSynchronized()那个版本就保障公平性而言,没有任何区别。 -If you look at the Synchronizer class above and look into this Lock implementation you will notice that threads are now blocked trying to access the lock() method, if more than one thread calls lock() simultanously. Second, if the lock is locked, the threads are blocked in the wait() call inside the while(isLocked) loop in the lock() method. Remember that a thread calling wait() releases the synchronization lock on the Lock instance, so threads waiting to enter lock() can now do so. The result is that multiple threads can end up having called wait() inside lock(). +(As stated earlier synchronized blocks makes no guarantees about what thread is being granted access if more than one thread is waiting to enter. Nor does wait() make any guarantees about what thread is awakened when notify() is called. So, the current version of the Lock class makes no different guarantees with respect to fairness than synchronized version of doSynchronized(). But we can change that.) -If you look back at the doSynchronized() method you will notice that the comment between lock() and unlock() states, that the code in between these two calls take a "long" time to execute. Let us further assume that this code takes long time to execute compared to entering the lock() method and calling wait() because the lock is locked. This means that the majority of the time waited to be able to lock the lock and enter the critical section is spent waiting in the wait() call inside the lock() method, not being blocked trying to enter the lock() method. +但我们能改变这种情况。当前的Lock类版本调用自己的wait()方法,如果每个线程在不同的对象上调用wait(),那么只有一个线程会在该对象上调用wait(),Lock类可以决定哪个对象能对其调用notify(),因此能做到有效的选择唤醒哪个线程。 -As stated earlier synchronized blocks makes no guarantees about what thread is being granted access if more than one thread is waiting to enter. Nor does wait() make any guarantees about what thread is awakened when notify() is called. So, the current version of the Lock class makes no different guarantees with respect to fairness than synchronized version of doSynchronized(). But we can change that. - -The current version of the Lock class calls its own wait() method. If instead each thread calls wait() on a separate object, so that only one thread has called wait() on each object, the Lock class can decide which of these objects to call notify() on, thereby effectively selecting exactly what thread to awaken. +(The current version of the Lock class calls its own wait() method. If instead each thread calls wait() on a separate object, so that only one thread has called wait() on each object, the Lock class can decide which of these objects to call notify() on, thereby effectively selecting exactly what thread to awaken.) ##公平锁(A Fair Lock) From aad374cdbb98a6bc50664b167500354f6a713964 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 13:36:19 +0800 Subject: [PATCH 197/524] Published with https://stackedit.io/ --- ...\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index f7feaf1..8933dd2 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -1,4 +1,4 @@ -#饥饿和公平(Starvation and Fairness) +#12.饥饿和公平(Starvation and Fairness) 如果一个线程由于CPU时间全部被其他线程抢占而得不到CPU时间,这就称为**饥饿(Starvation)**。这个线程因为得不到CPU机会而“饿死(starved to death)"。解决饥饿的方案称为**公平(Fairness)**--所有的线程都能公平地获得CPU时间。 From 6f2530f1201ba204537da637dc01f8c2ad36eafc Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 13:58:28 +0800 Subject: [PATCH 198/524] Published with https://stackedit.io/ --- ...245\351\245\277\345\222\214\345\205\254\345\271\263.md" | 7 +++++++ 1 file changed, 7 insertions(+) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index 8933dd2..5abe142 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -101,10 +101,17 @@ public class Lock{ ##公平锁(A Fair Lock) +下面的例子将之前Lock类改写成了公平锁的FairLock类。 + Below is shown the previous Lock class turned into a fair lock called FairLock. You will notice that the implementation has changed a bit with respect to synchronization and wait() / notify() compared to the Lock class shown earlier. Exactly how I arrived at this design beginning from the previous Lock class is a longer story involving several incremental design steps, each fixing the problem of the previous step: Nested Monitor Lockout, Slipped Conditions, and Missed Signals. That discussion is left out of this text to keep the text short, but each of the steps are discussed in the appropriate texts on the topic ( see the links above). What is important is, that every thread calling lock() is now queued, and only the first thread in the queue is allowed to lock the FairLock instance, if it is unlocked. All other threads are parked waiting until they reach the top of the queue. +如下图所示先前的锁类变成一个公平的锁叫FairLock。你会发现,实施已经改变了一下关于同步和wait()有/通知()相比前面介绍的锁类。 + +究竟我是怎么来到这个设计从以前的锁类开始是一个较长的故事,涉及多个增量的设计步骤,每个固定的上一步的问题:嵌套监控锁定,溜条件和未接信号。这种讨论留出这段文字保存在文本短,但是每个步骤都是在这个专题的相应文本(见上面的链接)进行讨论。最重要的是,每一个线程调用lock()现在是排队的,只有在队列中的第一个线程被允许锁定FairLock举例来说,如果它被解锁。所有其他线程都停在等待,直到它们到达队列的顶部。 + + ``` public class FairLock { private boolean isLocked = false; From 8d87fb1f42075607f7d63e8c75cfa11869d6aa8d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 14:15:42 +0800 Subject: [PATCH 199/524] Published with https://stackedit.io/ --- ...\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" | 2 -- 1 file changed, 2 deletions(-) diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index 5abe142..7074380 100644 --- "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -101,8 +101,6 @@ public class Lock{ ##公平锁(A Fair Lock) -下面的例子将之前Lock类改写成了公平锁的FairLock类。 - Below is shown the previous Lock class turned into a fair lock called FairLock. You will notice that the implementation has changed a bit with respect to synchronization and wait() / notify() compared to the Lock class shown earlier. Exactly how I arrived at this design beginning from the previous Lock class is a longer story involving several incremental design steps, each fixing the problem of the previous step: Nested Monitor Lockout, Slipped Conditions, and Missed Signals. That discussion is left out of this text to keep the text short, but each of the steps are discussed in the appropriate texts on the topic ( see the links above). What is important is, that every thread calling lock() is now queued, and only the first thread in the queue is allowed to lock the FairLock instance, if it is unlocked. All other threads are parked waiting until they reach the top of the queue. From 4d6a2484b5f75d7115cbf341dce18652c86ec84a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 14:16:31 +0800 Subject: [PATCH 200/524] Published with https://stackedit.io/ --- Java | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 Java diff --git a/Java b/Java new file mode 100644 index 0000000..872a216 --- /dev/null +++ b/Java @@ -0,0 +1,131 @@ +#13.嵌套管程锁死(Nested Monitor Lockout) + +How Nested Monitor Lockout Occurs + +Nested monitor lockout is a problem similar to deadlock. A nested monitor lockout occurs like this: + +Thread 1 synchronizes on A +Thread 1 synchronizes on B (while synchronized on A) +Thread 1 decides to wait for a signal from another thread before continuing +Thread 1 calls B.wait() thereby releasing the lock on B, but not A. + +Thread 2 needs to lock both A and B (in that sequence) + to send Thread 1 the signal. +Thread 2 cannot lock A, since Thread 1 still holds the lock on A. +Thread 2 remain blocked indefinately waiting for Thread1 + to release the lock on A + +Thread 1 remain blocked indefinately waiting for the signal from + Thread 2, thereby + never releasing the lock on A, that must be released to make + it possible for Thread 2 to send the signal to Thread 1, etc. +This may sound like a pretty theoretical situation, but look at the naive Lock implemenation below: + +//lock implementation with nested monitor lockout problem + +public class Lock{ + protected MonitorObject monitorObject = new MonitorObject(); + protected boolean isLocked = false; + + public void lock() throws InterruptedException{ + synchronized(this){ + while(isLocked){ + synchronized(this.monitorObject){ + this.monitorObject.wait(); + } + } + isLocked = true; + } + } + + public void unlock(){ + synchronized(this){ + this.isLocked = false; + synchronized(this.monitorObject){ + this.monitorObject.notify(); + } + } + } +} +Notice how the lock() method first synchronizes on "this", then synchronizes on the monitorObject member. If isLocked is false there is no problem. The thread does not call monitorObject.wait(). If isLocked is true however, the thread calling lock() is parked waiting in the monitorObject.wait() call. + +The problem with this is, that the call to monitorObject.wait() only releases the synchronization monitor on the monitorObject member, and not the synchronization monitor associated with "this". In other words, the thread that was just parked waiting is still holding the synchronization lock on "this". + +When the thread that locked the Lock in the first place tries to unlock it by calling unlock() it will be blocked trying to enter the synchronized(this) block in the unlock() method. It will remain blocked until the thread waiting in lock() leaves the synchronized(this) block. But the thread waiting in the lock() method will not leave that block until the isLocked is set to false, and a monitorObject.notify() is executed, as it happens in unlock(). + +Put shortly, the thread waiting in lock() needs an unlock() call to execute successfully for it to exit lock() and the synchronized blocks inside it. But, no thread can actually execute unlock() until the thread waiting in lock() leaves the outer synchronized block. + +This result is that any thread calling either lock() or unlock() will become blocked indefinately. This is called a nested monitor lockout. + +A More Realistic Example + +You may claim that you would never implement a lock like the one shown earlier. That you would not call wait() and notify() on an internal monitor object, but rather on the This is probably true. But there are situations in which designs like the one above may arise. For instance, if you were to implement fairness in a Lock. When doing so you want each thread to call wait() on each their own queue object, so that you can notify the threads one at a time. + +Look at this naive implementation of a fair lock: + +//Fair Lock implementation with nested monitor lockout problem + +public class FairLock { + private boolean isLocked = false; + private Thread lockingThread = null; + private List waitingThreads = + new ArrayList (); + + public void lock() throws InterruptedException{ + QueueObject queueObject = new QueueObject(); + + synchronized(this){ + waitingThreads.add(queueObject); + + while(isLocked || waitingThreads.get(0) != queueObject){ + + synchronized(queueObject){ + try{ + queueObject.wait(); + }catch(InterruptedException e){ + waitingThreads.remove(queueObject); + throw e; + } + } + } + waitingThreads.remove(queueObject); + isLocked = true; + lockingThread = Thread.currentThread(); + } + } + + public synchronized void unlock(){ + if(this.lockingThread != Thread.currentThread()){ + throw new IllegalMonitorStateException( + "Calling thread has not locked this lock"); + } + isLocked = false; + lockingThread = null; + if(waitingThreads.size() > 0){ + QueueObject queueObject = waitingThread.get(0); + synchronized(queueObject){ + queueObject.notify(); + } + } + } +} +public class QueueObject {} +At first glance this implementation may look fine, but notice how the lock() method calls queueObject.wait(); from inside two synchronized blocks. One synchronized on "this", and nested inside that, a block synchronized on the queueObject local variable. When a thread calls queueObject.wait()it releases the lock on the QueueObject instance, but not the lock associated with "this". + +Notice too, that the unlock() method is declared synchronized which equals a synchronized(this) block. This means, that if a thread is waiting inside lock() the monitor object associated with "this" will be locked by the waiting thread. All threads calling unlock() will remain blocked indefinately, waiting for the waiting thread to release the lock on "this". But this will never happen, since this only happens if a thread succeeds in sending a signal to the waiting thread, and this can only be sent by executing the unlock() method. + +And so, the FairLock implementation from above could lead to nested monitor lockout. A better implementation of a fair lock is described in the text Starvation and Fairness. + +Nested Monitor Lockout vs. Deadlock + +The result of nested monitor lockout and deadlock are pretty much the same: The threads involved end up blocked forever waiting for each other. + +The two situations are not equal though. As explained in the text on Deadlock a deadlock occurs when two threads obtain locks in different order. Thread 1 locks A, waits for B. Thread 2 has locked B, and now waits for A. As explained in the text on Deadlock Prevention deadlocks can be avoided by always locking the locks in the same order (Lock Ordering). However, a nested monitor lockout occurs exactly by two threads taking the locks in the same order. Thread 1 locks A and B, then releases B and waits for a signal from Thread 2. Thread 2 needs both A and B to send Thread 1 the signal. So, one thread is waiting for a signal, and another for a lock to be released. + +The difference is summed up here: + +In deadlock, two threads are waiting for each other to release locks. + +In nested monitor lockout, Thread 1 is holding a lock A, and waits +for a signal from Thread 2. Thread 2 needs the lock A to send the +signal to Thread 1. From a41f379ca37188add7e26c839bbf21cdcb49755a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 14:16:55 +0800 Subject: [PATCH 201/524] Delete Java --- Java | 131 ----------------------------------------------------------- 1 file changed, 131 deletions(-) delete mode 100644 Java diff --git a/Java b/Java deleted file mode 100644 index 872a216..0000000 --- a/Java +++ /dev/null @@ -1,131 +0,0 @@ -#13.嵌套管程锁死(Nested Monitor Lockout) - -How Nested Monitor Lockout Occurs - -Nested monitor lockout is a problem similar to deadlock. A nested monitor lockout occurs like this: - -Thread 1 synchronizes on A -Thread 1 synchronizes on B (while synchronized on A) -Thread 1 decides to wait for a signal from another thread before continuing -Thread 1 calls B.wait() thereby releasing the lock on B, but not A. - -Thread 2 needs to lock both A and B (in that sequence) - to send Thread 1 the signal. -Thread 2 cannot lock A, since Thread 1 still holds the lock on A. -Thread 2 remain blocked indefinately waiting for Thread1 - to release the lock on A - -Thread 1 remain blocked indefinately waiting for the signal from - Thread 2, thereby - never releasing the lock on A, that must be released to make - it possible for Thread 2 to send the signal to Thread 1, etc. -This may sound like a pretty theoretical situation, but look at the naive Lock implemenation below: - -//lock implementation with nested monitor lockout problem - -public class Lock{ - protected MonitorObject monitorObject = new MonitorObject(); - protected boolean isLocked = false; - - public void lock() throws InterruptedException{ - synchronized(this){ - while(isLocked){ - synchronized(this.monitorObject){ - this.monitorObject.wait(); - } - } - isLocked = true; - } - } - - public void unlock(){ - synchronized(this){ - this.isLocked = false; - synchronized(this.monitorObject){ - this.monitorObject.notify(); - } - } - } -} -Notice how the lock() method first synchronizes on "this", then synchronizes on the monitorObject member. If isLocked is false there is no problem. The thread does not call monitorObject.wait(). If isLocked is true however, the thread calling lock() is parked waiting in the monitorObject.wait() call. - -The problem with this is, that the call to monitorObject.wait() only releases the synchronization monitor on the monitorObject member, and not the synchronization monitor associated with "this". In other words, the thread that was just parked waiting is still holding the synchronization lock on "this". - -When the thread that locked the Lock in the first place tries to unlock it by calling unlock() it will be blocked trying to enter the synchronized(this) block in the unlock() method. It will remain blocked until the thread waiting in lock() leaves the synchronized(this) block. But the thread waiting in the lock() method will not leave that block until the isLocked is set to false, and a monitorObject.notify() is executed, as it happens in unlock(). - -Put shortly, the thread waiting in lock() needs an unlock() call to execute successfully for it to exit lock() and the synchronized blocks inside it. But, no thread can actually execute unlock() until the thread waiting in lock() leaves the outer synchronized block. - -This result is that any thread calling either lock() or unlock() will become blocked indefinately. This is called a nested monitor lockout. - -A More Realistic Example - -You may claim that you would never implement a lock like the one shown earlier. That you would not call wait() and notify() on an internal monitor object, but rather on the This is probably true. But there are situations in which designs like the one above may arise. For instance, if you were to implement fairness in a Lock. When doing so you want each thread to call wait() on each their own queue object, so that you can notify the threads one at a time. - -Look at this naive implementation of a fair lock: - -//Fair Lock implementation with nested monitor lockout problem - -public class FairLock { - private boolean isLocked = false; - private Thread lockingThread = null; - private List waitingThreads = - new ArrayList (); - - public void lock() throws InterruptedException{ - QueueObject queueObject = new QueueObject(); - - synchronized(this){ - waitingThreads.add(queueObject); - - while(isLocked || waitingThreads.get(0) != queueObject){ - - synchronized(queueObject){ - try{ - queueObject.wait(); - }catch(InterruptedException e){ - waitingThreads.remove(queueObject); - throw e; - } - } - } - waitingThreads.remove(queueObject); - isLocked = true; - lockingThread = Thread.currentThread(); - } - } - - public synchronized void unlock(){ - if(this.lockingThread != Thread.currentThread()){ - throw new IllegalMonitorStateException( - "Calling thread has not locked this lock"); - } - isLocked = false; - lockingThread = null; - if(waitingThreads.size() > 0){ - QueueObject queueObject = waitingThread.get(0); - synchronized(queueObject){ - queueObject.notify(); - } - } - } -} -public class QueueObject {} -At first glance this implementation may look fine, but notice how the lock() method calls queueObject.wait(); from inside two synchronized blocks. One synchronized on "this", and nested inside that, a block synchronized on the queueObject local variable. When a thread calls queueObject.wait()it releases the lock on the QueueObject instance, but not the lock associated with "this". - -Notice too, that the unlock() method is declared synchronized which equals a synchronized(this) block. This means, that if a thread is waiting inside lock() the monitor object associated with "this" will be locked by the waiting thread. All threads calling unlock() will remain blocked indefinately, waiting for the waiting thread to release the lock on "this". But this will never happen, since this only happens if a thread succeeds in sending a signal to the waiting thread, and this can only be sent by executing the unlock() method. - -And so, the FairLock implementation from above could lead to nested monitor lockout. A better implementation of a fair lock is described in the text Starvation and Fairness. - -Nested Monitor Lockout vs. Deadlock - -The result of nested monitor lockout and deadlock are pretty much the same: The threads involved end up blocked forever waiting for each other. - -The two situations are not equal though. As explained in the text on Deadlock a deadlock occurs when two threads obtain locks in different order. Thread 1 locks A, waits for B. Thread 2 has locked B, and now waits for A. As explained in the text on Deadlock Prevention deadlocks can be avoided by always locking the locks in the same order (Lock Ordering). However, a nested monitor lockout occurs exactly by two threads taking the locks in the same order. Thread 1 locks A and B, then releases B and waits for a signal from Thread 2. Thread 2 needs both A and B to send Thread 1 the signal. So, one thread is waiting for a signal, and another for a lock to be released. - -The difference is summed up here: - -In deadlock, two threads are waiting for each other to release locks. - -In nested monitor lockout, Thread 1 is holding a lock A, and waits -for a signal from Thread 2. Thread 2 needs the lock A to send the -signal to Thread 1. From 7e0f83f6b1079396110825bcefca716db65b212c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 14:17:43 +0800 Subject: [PATCH 202/524] Published with https://stackedit.io/ --- Java | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 Java diff --git a/Java b/Java new file mode 100644 index 0000000..872a216 --- /dev/null +++ b/Java @@ -0,0 +1,131 @@ +#13.嵌套管程锁死(Nested Monitor Lockout) + +How Nested Monitor Lockout Occurs + +Nested monitor lockout is a problem similar to deadlock. A nested monitor lockout occurs like this: + +Thread 1 synchronizes on A +Thread 1 synchronizes on B (while synchronized on A) +Thread 1 decides to wait for a signal from another thread before continuing +Thread 1 calls B.wait() thereby releasing the lock on B, but not A. + +Thread 2 needs to lock both A and B (in that sequence) + to send Thread 1 the signal. +Thread 2 cannot lock A, since Thread 1 still holds the lock on A. +Thread 2 remain blocked indefinately waiting for Thread1 + to release the lock on A + +Thread 1 remain blocked indefinately waiting for the signal from + Thread 2, thereby + never releasing the lock on A, that must be released to make + it possible for Thread 2 to send the signal to Thread 1, etc. +This may sound like a pretty theoretical situation, but look at the naive Lock implemenation below: + +//lock implementation with nested monitor lockout problem + +public class Lock{ + protected MonitorObject monitorObject = new MonitorObject(); + protected boolean isLocked = false; + + public void lock() throws InterruptedException{ + synchronized(this){ + while(isLocked){ + synchronized(this.monitorObject){ + this.monitorObject.wait(); + } + } + isLocked = true; + } + } + + public void unlock(){ + synchronized(this){ + this.isLocked = false; + synchronized(this.monitorObject){ + this.monitorObject.notify(); + } + } + } +} +Notice how the lock() method first synchronizes on "this", then synchronizes on the monitorObject member. If isLocked is false there is no problem. The thread does not call monitorObject.wait(). If isLocked is true however, the thread calling lock() is parked waiting in the monitorObject.wait() call. + +The problem with this is, that the call to monitorObject.wait() only releases the synchronization monitor on the monitorObject member, and not the synchronization monitor associated with "this". In other words, the thread that was just parked waiting is still holding the synchronization lock on "this". + +When the thread that locked the Lock in the first place tries to unlock it by calling unlock() it will be blocked trying to enter the synchronized(this) block in the unlock() method. It will remain blocked until the thread waiting in lock() leaves the synchronized(this) block. But the thread waiting in the lock() method will not leave that block until the isLocked is set to false, and a monitorObject.notify() is executed, as it happens in unlock(). + +Put shortly, the thread waiting in lock() needs an unlock() call to execute successfully for it to exit lock() and the synchronized blocks inside it. But, no thread can actually execute unlock() until the thread waiting in lock() leaves the outer synchronized block. + +This result is that any thread calling either lock() or unlock() will become blocked indefinately. This is called a nested monitor lockout. + +A More Realistic Example + +You may claim that you would never implement a lock like the one shown earlier. That you would not call wait() and notify() on an internal monitor object, but rather on the This is probably true. But there are situations in which designs like the one above may arise. For instance, if you were to implement fairness in a Lock. When doing so you want each thread to call wait() on each their own queue object, so that you can notify the threads one at a time. + +Look at this naive implementation of a fair lock: + +//Fair Lock implementation with nested monitor lockout problem + +public class FairLock { + private boolean isLocked = false; + private Thread lockingThread = null; + private List waitingThreads = + new ArrayList (); + + public void lock() throws InterruptedException{ + QueueObject queueObject = new QueueObject(); + + synchronized(this){ + waitingThreads.add(queueObject); + + while(isLocked || waitingThreads.get(0) != queueObject){ + + synchronized(queueObject){ + try{ + queueObject.wait(); + }catch(InterruptedException e){ + waitingThreads.remove(queueObject); + throw e; + } + } + } + waitingThreads.remove(queueObject); + isLocked = true; + lockingThread = Thread.currentThread(); + } + } + + public synchronized void unlock(){ + if(this.lockingThread != Thread.currentThread()){ + throw new IllegalMonitorStateException( + "Calling thread has not locked this lock"); + } + isLocked = false; + lockingThread = null; + if(waitingThreads.size() > 0){ + QueueObject queueObject = waitingThread.get(0); + synchronized(queueObject){ + queueObject.notify(); + } + } + } +} +public class QueueObject {} +At first glance this implementation may look fine, but notice how the lock() method calls queueObject.wait(); from inside two synchronized blocks. One synchronized on "this", and nested inside that, a block synchronized on the queueObject local variable. When a thread calls queueObject.wait()it releases the lock on the QueueObject instance, but not the lock associated with "this". + +Notice too, that the unlock() method is declared synchronized which equals a synchronized(this) block. This means, that if a thread is waiting inside lock() the monitor object associated with "this" will be locked by the waiting thread. All threads calling unlock() will remain blocked indefinately, waiting for the waiting thread to release the lock on "this". But this will never happen, since this only happens if a thread succeeds in sending a signal to the waiting thread, and this can only be sent by executing the unlock() method. + +And so, the FairLock implementation from above could lead to nested monitor lockout. A better implementation of a fair lock is described in the text Starvation and Fairness. + +Nested Monitor Lockout vs. Deadlock + +The result of nested monitor lockout and deadlock are pretty much the same: The threads involved end up blocked forever waiting for each other. + +The two situations are not equal though. As explained in the text on Deadlock a deadlock occurs when two threads obtain locks in different order. Thread 1 locks A, waits for B. Thread 2 has locked B, and now waits for A. As explained in the text on Deadlock Prevention deadlocks can be avoided by always locking the locks in the same order (Lock Ordering). However, a nested monitor lockout occurs exactly by two threads taking the locks in the same order. Thread 1 locks A and B, then releases B and waits for a signal from Thread 2. Thread 2 needs both A and B to send Thread 1 the signal. So, one thread is waiting for a signal, and another for a lock to be released. + +The difference is summed up here: + +In deadlock, two threads are waiting for each other to release locks. + +In nested monitor lockout, Thread 1 is holding a lock A, and waits +for a signal from Thread 2. Thread 2 needs the lock A to send the +signal to Thread 1. From 2639f3ac3dae633ee01db8a021c5b0bb67b881f7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 14:18:17 +0800 Subject: [PATCH 203/524] Published with https://stackedit.io/ From 36bc6c2af04b086213794fdd50f827af00616b4b Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 14:35:28 +0800 Subject: [PATCH 204/524] Published with https://stackedit.io/ --- ...41\347\250\213\351\224\201\346\255\273.md" | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" index 872a216..d7f6f77 100644 --- "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" +++ "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" @@ -1,26 +1,26 @@ #13.嵌套管程锁死(Nested Monitor Lockout) -How Nested Monitor Lockout Occurs +##嵌套管程锁死如何发生 +嵌套管程锁死类似与死锁。它发生的情况类似这样: Nested monitor lockout is a problem similar to deadlock. A nested monitor lockout occurs like this: -Thread 1 synchronizes on A -Thread 1 synchronizes on B (while synchronized on A) -Thread 1 decides to wait for a signal from another thread before continuing -Thread 1 calls B.wait() thereby releasing the lock on B, but not A. +``` +线程1 获得对象A的锁 +线程1 获得对象B的锁(同时持有对象A的锁) +线程1 决定等待另一个线程的信号再继续 +线程1 调用B.wait()方法释放对象B的锁,当仍然拥有对象A的锁 -Thread 2 needs to lock both A and B (in that sequence) - to send Thread 1 the signal. -Thread 2 cannot lock A, since Thread 1 still holds the lock on A. -Thread 2 remain blocked indefinately waiting for Thread1 - to release the lock on A +线程2 需要依次获得对象A和对象B的锁 +线程2 由于对象A的锁由线程1持有,线程2进入阻塞状态 +线程2 一直被阻塞,等待线程1释放对象A的锁 -Thread 1 remain blocked indefinately waiting for the signal from - Thread 2, thereby - never releasing the lock on A, that must be released to make - it possible for Thread 2 to send the signal to Thread 1, etc. -This may sound like a pretty theoretical situation, but look at the naive Lock implemenation below: +线程1 由于需要等待线程2的信号而一直陷入等待状态,因此一直没有释放对象A的锁,而线程2需要持有对象A的锁才能给线程1发送信号... +``` +这听起来像是纯理论的场景,不妨看下这个比较幼稚的Lock实现: + +```Java //lock implementation with nested monitor lockout problem public class Lock{ @@ -47,6 +47,8 @@ public class Lock{ } } } +``` + Notice how the lock() method first synchronizes on "this", then synchronizes on the monitorObject member. If isLocked is false there is no problem. The thread does not call monitorObject.wait(). If isLocked is true however, the thread calling lock() is parked waiting in the monitorObject.wait() call. The problem with this is, that the call to monitorObject.wait() only releases the synchronization monitor on the monitorObject member, and not the synchronization monitor associated with "this". In other words, the thread that was just parked waiting is still holding the synchronization lock on "this". From 75764bfc9e3377e691cb7da2f282d54c69c1d993 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 14:44:37 +0800 Subject: [PATCH 205/524] Published with https://stackedit.io/ --- ...45\227\347\256\241\347\250\213\351\224\201\346\255\273.md" | 4 ++++ 1 file changed, 4 insertions(+) diff --git "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" index d7f6f77..c5ff8f0 100644 --- "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" +++ "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" @@ -49,6 +49,10 @@ public class Lock{ } ``` +注意`lock()`方法中,首先获得this的锁,然后获得`monitorObject`的锁。当`isLock`为`false`时不会有什么问题,此时线程不会调用`monitorObject.wait()`方法。而当`isLock`为`true`时,线程会调用`monitorObjct.wait()`方法而陷入等待状态。 + + + Notice how the lock() method first synchronizes on "this", then synchronizes on the monitorObject member. If isLocked is false there is no problem. The thread does not call monitorObject.wait(). If isLocked is true however, the thread calling lock() is parked waiting in the monitorObject.wait() call. The problem with this is, that the call to monitorObject.wait() only releases the synchronization monitor on the monitorObject member, and not the synchronization monitor associated with "this". In other words, the thread that was just parked waiting is still holding the synchronization lock on "this". From 1068a531f177cafb259f0cb3933e066c0a81e6a7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 14:58:13 +0800 Subject: [PATCH 206/524] Published with https://stackedit.io/ --- ...\227\347\256\241\347\250\213\351\224\201\346\255\273.md" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" index c5ff8f0..25e67e9 100644 --- "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" +++ "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" @@ -51,13 +51,13 @@ public class Lock{ 注意`lock()`方法中,首先获得this的锁,然后获得`monitorObject`的锁。当`isLock`为`false`时不会有什么问题,此时线程不会调用`monitorObject.wait()`方法。而当`isLock`为`true`时,线程会调用`monitorObjct.wait()`方法而陷入等待状态。 +问题就在于,调用`monitorObject.wait()`方法会释放monitorObject的锁,而不会释放this上的锁。换言之,线程在嵌入等待状态的同时,仍然持有this的锁。 +当一个线程调用`lock()`方法成功锁住后,再次调用`unlock()`方法时则会在进入this的同步块时陷入阻塞状态。它只有当陷入等待状态的线程释放this的锁才能够进入this的同步块。而嵌入等待的线程却需要嵌入阻塞的线程将isLock设置为false和调用`monitorObject.notify()` 才会释放this的锁。 -Notice how the lock() method first synchronizes on "this", then synchronizes on the monitorObject member. If isLocked is false there is no problem. The thread does not call monitorObject.wait(). If isLocked is true however, the thread calling lock() is parked waiting in the monitorObject.wait() call. +这导致的结果就是:任意调用`lock()`和`unlock()`的线程都会陷入无止境的阻塞和等待状态。这种线程称之为**嵌套管程锁死**。 -The problem with this is, that the call to monitorObject.wait() only releases the synchronization monitor on the monitorObject member, and not the synchronization monitor associated with "this". In other words, the thread that was just parked waiting is still holding the synchronization lock on "this". -When the thread that locked the Lock in the first place tries to unlock it by calling unlock() it will be blocked trying to enter the synchronized(this) block in the unlock() method. It will remain blocked until the thread waiting in lock() leaves the synchronized(this) block. But the thread waiting in the lock() method will not leave that block until the isLocked is set to false, and a monitorObject.notify() is executed, as it happens in unlock(). Put shortly, the thread waiting in lock() needs an unlock() call to execute successfully for it to exit lock() and the synchronized blocks inside it. But, no thread can actually execute unlock() until the thread waiting in lock() leaves the outer synchronized block. From 0a216ed33fba9437b16e9ff5bd87653d34a79e5a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 15:07:25 +0800 Subject: [PATCH 207/524] Published with https://stackedit.io/ --- ...347\256\241\347\250\213\351\224\201\346\255\273.md" | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" index 25e67e9..ec3d3d9 100644 --- "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" +++ "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" @@ -55,15 +55,11 @@ public class Lock{ 当一个线程调用`lock()`方法成功锁住后,再次调用`unlock()`方法时则会在进入this的同步块时陷入阻塞状态。它只有当陷入等待状态的线程释放this的锁才能够进入this的同步块。而嵌入等待的线程却需要嵌入阻塞的线程将isLock设置为false和调用`monitorObject.notify()` 才会释放this的锁。 -这导致的结果就是:任意调用`lock()`和`unlock()`的线程都会陷入无止境的阻塞和等待状态。这种线程称之为**嵌套管程锁死**。 - - +简而言之,调用`lock()`方法而陷入等待的线程1需要调用了`unlock()`方法的线程2正常地执行`unlock()`方法,但线程2却需要线程1释放锁才能够正确地执行下去。 -Put shortly, the thread waiting in lock() needs an unlock() call to execute successfully for it to exit lock() and the synchronized blocks inside it. But, no thread can actually execute unlock() until the thread waiting in lock() leaves the outer synchronized block. - -This result is that any thread calling either lock() or unlock() will become blocked indefinately. This is called a nested monitor lockout. +这导致的结果就是:任意调用`lock()`和`unlock()`的线程都会陷入无止境的阻塞和等待状态。这种线程称之为**嵌套管程锁死**。 -A More Realistic Example +##更现实的例子(A More Realistic Example) You may claim that you would never implement a lock like the one shown earlier. That you would not call wait() and notify() on an internal monitor object, but rather on the This is probably true. But there are situations in which designs like the one above may arise. For instance, if you were to implement fairness in a Lock. When doing so you want each thread to call wait() on each their own queue object, so that you can notify the threads one at a time. From 1604cc4506633cff5d7b3c9acfaca8ca326df7e5 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 15:19:30 +0800 Subject: [PATCH 208/524] Published with https://stackedit.io/ --- ...7\347\256\241\347\250\213\351\224\201\346\255\273.md" | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" index ec3d3d9..a3cd6f3 100644 --- "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" +++ "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" @@ -61,10 +61,11 @@ public class Lock{ ##更现实的例子(A More Realistic Example) -You may claim that you would never implement a lock like the one shown earlier. That you would not call wait() and notify() on an internal monitor object, but rather on the This is probably true. But there are situations in which designs like the one above may arise. For instance, if you were to implement fairness in a Lock. When doing so you want each thread to call wait() on each their own queue object, so that you can notify the threads one at a time. +也许你会抱怨,你永远也不会实现像上面那样的锁。也许你不会像上面一样调用**嵌套管程(内部监听器)**对象的`wait()`和`notify()`方法,当完全有可能会调用在外层的this对象上。(You may claim that you would never implement a lock like the one shown earlier. That you would not call wait() and notify() on an internal monitor object, but rather on the This is probably true. )有很多类似上面的例子。例如,如果你需要实现一个公平锁。你可能希望每个线程在它们各自的QueueObject上调用`wait()`,这样就可以每次唤醒一个线程。 -Look at this naive implementation of a fair lock: +下面的公平锁实现: +``` //Fair Lock implementation with nested monitor lockout problem public class FairLock { @@ -112,13 +113,15 @@ public class FairLock { } } public class QueueObject {} +``` + At first glance this implementation may look fine, but notice how the lock() method calls queueObject.wait(); from inside two synchronized blocks. One synchronized on "this", and nested inside that, a block synchronized on the queueObject local variable. When a thread calls queueObject.wait()it releases the lock on the QueueObject instance, but not the lock associated with "this". Notice too, that the unlock() method is declared synchronized which equals a synchronized(this) block. This means, that if a thread is waiting inside lock() the monitor object associated with "this" will be locked by the waiting thread. All threads calling unlock() will remain blocked indefinately, waiting for the waiting thread to release the lock on "this". But this will never happen, since this only happens if a thread succeeds in sending a signal to the waiting thread, and this can only be sent by executing the unlock() method. And so, the FairLock implementation from above could lead to nested monitor lockout. A better implementation of a fair lock is described in the text Starvation and Fairness. -Nested Monitor Lockout vs. Deadlock +##嵌套管程锁死 vs 死锁(Nested Monitor Lockout vs. Deadlock) The result of nested monitor lockout and deadlock are pretty much the same: The threads involved end up blocked forever waiting for each other. From 664010dc044fcc4b56f20174f712d9b75f071490 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 15:22:58 +0800 Subject: [PATCH 209/524] Published with https://stackedit.io/ --- ...7\347\256\241\347\250\213\351\224\201\346\255\273.md" | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" index a3cd6f3..63f1351 100644 --- "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" +++ "b/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" @@ -127,10 +127,7 @@ The result of nested monitor lockout and deadlock are pretty much the same: The The two situations are not equal though. As explained in the text on Deadlock a deadlock occurs when two threads obtain locks in different order. Thread 1 locks A, waits for B. Thread 2 has locked B, and now waits for A. As explained in the text on Deadlock Prevention deadlocks can be avoided by always locking the locks in the same order (Lock Ordering). However, a nested monitor lockout occurs exactly by two threads taking the locks in the same order. Thread 1 locks A and B, then releases B and waits for a signal from Thread 2. Thread 2 needs both A and B to send Thread 1 the signal. So, one thread is waiting for a signal, and another for a lock to be released. -The difference is summed up here: +两者的不同点如下: -In deadlock, two threads are waiting for each other to release locks. - -In nested monitor lockout, Thread 1 is holding a lock A, and waits -for a signal from Thread 2. Thread 2 needs the lock A to send the -signal to Thread 1. +* 在死锁中,两个线程互相等待对方释放锁。 +* 在嵌套管程锁死中,线程1持有锁A,并等待线程2的信号,而线程2需要锁A才能够发送信号给线程1. \ No newline at end of file From e55f75994352d199fb4e05b5b703796f79445159 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 15:24:53 +0800 Subject: [PATCH 210/524] Published with https://stackedit.io/ --- ...va\344\270\255\347\232\204\351\224\201.md" | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 "Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" new file mode 100644 index 0000000..0cbb74a --- /dev/null +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -0,0 +1,169 @@ +#Java中的锁 + +A lock is a thread synchronization mechanism like synchronized blocks except locks can be more sophisticated than Java's synchronized blocks. Locks (and other more advanced synchronization mechanisms) are created using synchronized blocks, so it is not like we can get totally rid of the synchronized keyword. + +From Java 5 the package java.util.concurrent.locks contains several lock implementations, so you may not have to implement your own locks. But you will still need to know how to use them, and it can still be useful to know the theory behind their implementation. For more details, see my tutorial on the java.util.concurrent.locks.Lock interface. + +A Simple Lock + +Let's start out by looking at a synchronized block of Java code: + +public class Counter{ + + private int count = 0; + + public int inc(){ + synchronized(this){ + return ++count; + } + } +} +Notice the synchronized(this) block in the inc() method. This block makes sure that only one thread can execute the return ++count at a time. The code in the synchronized block could have been more advanced, but the simple ++count suffices to get the point across. + +The Counter class could have been written like this instead, using a Lock instead of a synchronized block: + +public class Counter{ + + private Lock lock = new Lock(); + private int count = 0; + + public int inc(){ + lock.lock(); + int newCount = ++count; + lock.unlock(); + return newCount; + } +} +The lock() method locks the Lock instance so that all threads calling lock() are blocked until unlock() is executed. + +Here is a simple Lock implementation: + +public class Lock{ + + private boolean isLocked = false; + + public synchronized void lock() + throws InterruptedException{ + while(isLocked){ + wait(); + } + isLocked = true; + } + + public synchronized void unlock(){ + isLocked = false; + notify(); + } +} +Notice the while(isLocked) loop, which is also called a "spin lock". Spin locks and the methods wait() and notify() are covered in more detail in the text Thread Signaling. While isLocked is true, the thread calling lock() is parked waiting in the wait() call. In case the thread should return unexpectedly from the wait() call without having received a notify() call (AKA a Spurious Wakeup) the thread re-checks the isLocked condition to see if it is safe to proceed or not, rather than just assume that being awakened means it is safe to proceed. If isLocked is false, the thread exits the while(isLocked) loop, and sets isLocked back to true, to lock the Lock instance for other threads calling lock(). + +When the thread is done with the code in the critical section (the code between lock() and unlock()), the thread calls unlock(). Executing unlock() sets isLocked back to false, and notifies (awakens) one of the threads waiting in the wait() call in the lock() method, if any. + +Lock Reentrance + +Synchronized blocks in Java are reentrant. This means, that if a Java thread enters a synchronized block of code, and thereby take the lock on the monitor object the block is synchronized on, the thread can enter other Java code blocks synchronized on the same monitor object. Here is an example: + +public class Reentrant{ + + public synchronized outer(){ + inner(); + } + + public synchronized inner(){ + //do something + } +} +Notice how both outer() and inner() are declared synchronized, which in Java is equivalent to a synchronized(this) block. If a thread calls outer() there is no problem calling inner() from inside outer(), since both methods (or blocks) are synchronized on the same monitor object ("this"). If a thread already holds the lock on a monitor object, it has access to all blocks synchronized on the same monitor object. This is called reentrance. The thread can reenter any block of code for which it already holds the lock. + +The lock implementation shown earlier is not reentrant. If we rewrite the Reentrant class like below, the thread calling outer() will be blocked inside the lock.lock() in the inner() method. + +public class Reentrant2{ + + Lock lock = new Lock(); + + public outer(){ + lock.lock(); + inner(); + lock.unlock(); + } + + public synchronized inner(){ + lock.lock(); + //do something + lock.unlock(); + } +} +A thread calling outer() will first lock the Lock instance. Then it will call inner(). Inside the inner() method the thread will again try to lock the Lock instance. This will fail (meaning the thread will be blocked), since the Lock instance was locked already in the outer() method. + +The reason the thread will be blocked the second time it calls lock() without having called unlock() in between, is apparent when we look at the lock() implementation: + +public class Lock{ + + boolean isLocked = false; + + public synchronized void lock() + throws InterruptedException{ + while(isLocked){ + wait(); + } + isLocked = true; + } + + ... +} +It is the condition inside the while loop (spin lock) that determines if a thread is allowed to exit the lock() method or not. Currently the condition is that isLocked must be false for this to be allowed, regardless of what thread locked it. + +To make the Lock class reentrant we need to make a small change: + +public class Lock{ + + boolean isLocked = false; + Thread lockedBy = null; + int lockedCount = 0; + + public synchronized void lock() + throws InterruptedException{ + Thread callingThread = Thread.currentThread(); + while(isLocked && lockedBy != callingThread){ + wait(); + } + isLocked = true; + lockedCount++; + lockedBy = callingThread; + } + + + public synchronized void unlock(){ + if(Thread.curentThread() == this.lockedBy){ + lockedCount--; + + if(lockedCount == 0){ + isLocked = false; + notify(); + } + } + } + + ... +} +Notice how the while loop (spin lock) now also takes the thread that locked the Lock instance into consideration. If either the lock is unlocked (isLocked = false) or the calling thread is the thread that locked the Lock instance, the while loop will not execute, and the thread calling lock() will be allowed to exit the method. + +Additionally, we need to count the number of times the lock has been locked by the same thread. Otherwise, a single call to unlock() will unlock the lock, even if the lock has been locked multiple times. We don't want the lock to be unloced until the thread that locked it, has executed the same amount of unlock() calls as lock() calls. + +The Lock class is now reentrant. + +Lock Fairness + +Java's synchronized blocks makes no guarantees about the sequence in which threads trying to enter them are granted access. Therefore, if many threads are constantly competing for access to the same synchronized block, there is a risk that one or more of the threads are never granted access - that access is always granted to other threads. This is called starvation. To avoid this a Lock should be fair. Since the Lock implementations shown in this text uses synchronized blocks internally, they do not guarantee fairness. Starvation and fairness are discussed in more detail in the text Starvation and Fairness. + +Calling unlock() From a finally-clause + +When guarding a critical section with a Lock, and the critical section may throw exceptions, it is important to call the unlock() method from inside a finally-clause. Doing so makes sure that the Lock is unlocked so other threads can lock it. Here is an example: + +lock.lock(); +try{ + //do critical section code, which may throw exception +} finally { + lock.unlock(); +} +This little construct makes sure that the Lock is unlocked in case an exception is thrown from the code in the critical section. If unlock() was not called from inside a finally-clause, and an exception was thrown from the critical section, the Lock would remain locked forever, causing all threads calling lock() on that Lock instance to halt indefinately. \ No newline at end of file From f28fad65d0aa233af15473d6717fe1556e74e88d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 15:25:52 +0800 Subject: [PATCH 211/524] Published with https://stackedit.io/ From 9bedb38bf1a0f03b9d9e55d4624a0d6193a6fe48 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 15:26:40 +0800 Subject: [PATCH 212/524] =?UTF-8?q?Delete=2015Java=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E9=94=81.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...va\344\270\255\347\232\204\351\224\201.md" | 169 ------------------ 1 file changed, 169 deletions(-) delete mode 100644 "Java-Concurrency/15Java\344\270\255\347\232\204\351\224\201.md" diff --git "a/Java-Concurrency/15Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15Java\344\270\255\347\232\204\351\224\201.md" deleted file mode 100644 index 0cbb74a..0000000 --- "a/Java-Concurrency/15Java\344\270\255\347\232\204\351\224\201.md" +++ /dev/null @@ -1,169 +0,0 @@ -#Java中的锁 - -A lock is a thread synchronization mechanism like synchronized blocks except locks can be more sophisticated than Java's synchronized blocks. Locks (and other more advanced synchronization mechanisms) are created using synchronized blocks, so it is not like we can get totally rid of the synchronized keyword. - -From Java 5 the package java.util.concurrent.locks contains several lock implementations, so you may not have to implement your own locks. But you will still need to know how to use them, and it can still be useful to know the theory behind their implementation. For more details, see my tutorial on the java.util.concurrent.locks.Lock interface. - -A Simple Lock - -Let's start out by looking at a synchronized block of Java code: - -public class Counter{ - - private int count = 0; - - public int inc(){ - synchronized(this){ - return ++count; - } - } -} -Notice the synchronized(this) block in the inc() method. This block makes sure that only one thread can execute the return ++count at a time. The code in the synchronized block could have been more advanced, but the simple ++count suffices to get the point across. - -The Counter class could have been written like this instead, using a Lock instead of a synchronized block: - -public class Counter{ - - private Lock lock = new Lock(); - private int count = 0; - - public int inc(){ - lock.lock(); - int newCount = ++count; - lock.unlock(); - return newCount; - } -} -The lock() method locks the Lock instance so that all threads calling lock() are blocked until unlock() is executed. - -Here is a simple Lock implementation: - -public class Lock{ - - private boolean isLocked = false; - - public synchronized void lock() - throws InterruptedException{ - while(isLocked){ - wait(); - } - isLocked = true; - } - - public synchronized void unlock(){ - isLocked = false; - notify(); - } -} -Notice the while(isLocked) loop, which is also called a "spin lock". Spin locks and the methods wait() and notify() are covered in more detail in the text Thread Signaling. While isLocked is true, the thread calling lock() is parked waiting in the wait() call. In case the thread should return unexpectedly from the wait() call without having received a notify() call (AKA a Spurious Wakeup) the thread re-checks the isLocked condition to see if it is safe to proceed or not, rather than just assume that being awakened means it is safe to proceed. If isLocked is false, the thread exits the while(isLocked) loop, and sets isLocked back to true, to lock the Lock instance for other threads calling lock(). - -When the thread is done with the code in the critical section (the code between lock() and unlock()), the thread calls unlock(). Executing unlock() sets isLocked back to false, and notifies (awakens) one of the threads waiting in the wait() call in the lock() method, if any. - -Lock Reentrance - -Synchronized blocks in Java are reentrant. This means, that if a Java thread enters a synchronized block of code, and thereby take the lock on the monitor object the block is synchronized on, the thread can enter other Java code blocks synchronized on the same monitor object. Here is an example: - -public class Reentrant{ - - public synchronized outer(){ - inner(); - } - - public synchronized inner(){ - //do something - } -} -Notice how both outer() and inner() are declared synchronized, which in Java is equivalent to a synchronized(this) block. If a thread calls outer() there is no problem calling inner() from inside outer(), since both methods (or blocks) are synchronized on the same monitor object ("this"). If a thread already holds the lock on a monitor object, it has access to all blocks synchronized on the same monitor object. This is called reentrance. The thread can reenter any block of code for which it already holds the lock. - -The lock implementation shown earlier is not reentrant. If we rewrite the Reentrant class like below, the thread calling outer() will be blocked inside the lock.lock() in the inner() method. - -public class Reentrant2{ - - Lock lock = new Lock(); - - public outer(){ - lock.lock(); - inner(); - lock.unlock(); - } - - public synchronized inner(){ - lock.lock(); - //do something - lock.unlock(); - } -} -A thread calling outer() will first lock the Lock instance. Then it will call inner(). Inside the inner() method the thread will again try to lock the Lock instance. This will fail (meaning the thread will be blocked), since the Lock instance was locked already in the outer() method. - -The reason the thread will be blocked the second time it calls lock() without having called unlock() in between, is apparent when we look at the lock() implementation: - -public class Lock{ - - boolean isLocked = false; - - public synchronized void lock() - throws InterruptedException{ - while(isLocked){ - wait(); - } - isLocked = true; - } - - ... -} -It is the condition inside the while loop (spin lock) that determines if a thread is allowed to exit the lock() method or not. Currently the condition is that isLocked must be false for this to be allowed, regardless of what thread locked it. - -To make the Lock class reentrant we need to make a small change: - -public class Lock{ - - boolean isLocked = false; - Thread lockedBy = null; - int lockedCount = 0; - - public synchronized void lock() - throws InterruptedException{ - Thread callingThread = Thread.currentThread(); - while(isLocked && lockedBy != callingThread){ - wait(); - } - isLocked = true; - lockedCount++; - lockedBy = callingThread; - } - - - public synchronized void unlock(){ - if(Thread.curentThread() == this.lockedBy){ - lockedCount--; - - if(lockedCount == 0){ - isLocked = false; - notify(); - } - } - } - - ... -} -Notice how the while loop (spin lock) now also takes the thread that locked the Lock instance into consideration. If either the lock is unlocked (isLocked = false) or the calling thread is the thread that locked the Lock instance, the while loop will not execute, and the thread calling lock() will be allowed to exit the method. - -Additionally, we need to count the number of times the lock has been locked by the same thread. Otherwise, a single call to unlock() will unlock the lock, even if the lock has been locked multiple times. We don't want the lock to be unloced until the thread that locked it, has executed the same amount of unlock() calls as lock() calls. - -The Lock class is now reentrant. - -Lock Fairness - -Java's synchronized blocks makes no guarantees about the sequence in which threads trying to enter them are granted access. Therefore, if many threads are constantly competing for access to the same synchronized block, there is a risk that one or more of the threads are never granted access - that access is always granted to other threads. This is called starvation. To avoid this a Lock should be fair. Since the Lock implementations shown in this text uses synchronized blocks internally, they do not guarantee fairness. Starvation and fairness are discussed in more detail in the text Starvation and Fairness. - -Calling unlock() From a finally-clause - -When guarding a critical section with a Lock, and the critical section may throw exceptions, it is important to call the unlock() method from inside a finally-clause. Doing so makes sure that the Lock is unlocked so other threads can lock it. Here is an example: - -lock.lock(); -try{ - //do critical section code, which may throw exception -} finally { - lock.unlock(); -} -This little construct makes sure that the Lock is unlocked in case an exception is thrown from the code in the critical section. If unlock() was not called from inside a finally-clause, and an exception was thrown from the critical section, the Lock would remain locked forever, causing all threads calling lock() on that Lock instance to halt indefinately. \ No newline at end of file From 68b79467ad7431fc8e9515357481434383935a63 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 15:30:45 +0800 Subject: [PATCH 213/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 0cbb74a..baecd34 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -4,7 +4,7 @@ A lock is a thread synchronization mechanism like synchronized blocks except loc From Java 5 the package java.util.concurrent.locks contains several lock implementations, so you may not have to implement your own locks. But you will still need to know how to use them, and it can still be useful to know the theory behind their implementation. For more details, see my tutorial on the java.util.concurrent.locks.Lock interface. -A Simple Lock +##简单锁(A Simple Lock) Let's start out by looking at a synchronized block of Java code: @@ -59,7 +59,7 @@ Notice the while(isLocked) loop, which is also called a "spin lock". Spin locks When the thread is done with the code in the critical section (the code between lock() and unlock()), the thread calls unlock(). Executing unlock() sets isLocked back to false, and notifies (awakens) one of the threads waiting in the wait() call in the lock() method, if any. -Lock Reentrance +##重得锁(Lock Reentrance) Synchronized blocks in Java are reentrant. This means, that if a Java thread enters a synchronized block of code, and thereby take the lock on the monitor object the block is synchronized on, the thread can enter other Java code blocks synchronized on the same monitor object. Here is an example: @@ -152,7 +152,7 @@ Additionally, we need to count the number of times the lock has been locked by t The Lock class is now reentrant. -Lock Fairness +## 公平锁(Lock Fairness) Java's synchronized blocks makes no guarantees about the sequence in which threads trying to enter them are granted access. Therefore, if many threads are constantly competing for access to the same synchronized block, there is a risk that one or more of the threads are never granted access - that access is always granted to other threads. This is called starvation. To avoid this a Lock should be fair. Since the Lock implementations shown in this text uses synchronized blocks internally, they do not guarantee fairness. Starvation and fairness are discussed in more detail in the text Starvation and Fairness. From 430da971873c6b8b4c955ab79605453ff8ffdf42 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 15:49:45 +0800 Subject: [PATCH 214/524] Published with https://stackedit.io/ --- ...va\344\270\255\347\232\204\351\224\201.md" | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index baecd34..067f04f 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -1,13 +1,14 @@ #Java中的锁 -A lock is a thread synchronization mechanism like synchronized blocks except locks can be more sophisticated than Java's synchronized blocks. Locks (and other more advanced synchronization mechanisms) are created using synchronized blocks, so it is not like we can get totally rid of the synchronized keyword. +**锁**跟**synchronized**的一样,是Java中的一种同步机制,但要比synchronized复杂得多。在Java 5之前,锁(以及其它更高级的线程同步机制)是由synchronized同步块的方式实现的,我们还不能完全摆脱synchronized关键字。 -From Java 5 the package java.util.concurrent.locks contains several lock implementations, so you may not have to implement your own locks. But you will still need to know how to use them, and it can still be useful to know the theory behind their implementation. For more details, see my tutorial on the java.util.concurrent.locks.Lock interface. +在Java 5的`java.util.concurrent.locks`包有多种锁的实现,因此,你并不需要自己去实现锁。当你仍然需要知道如何使用它们以及了解它们的实现原理。 -##简单锁(A Simple Lock) +##一个简单的锁(A Simple Lock) -Let's start out by looking at a synchronized block of Java code: +让我们从一个简单的Java synchronized块开始: +```Java public class Counter{ private int count = 0; @@ -18,10 +19,13 @@ public class Counter{ } } } -Notice the synchronized(this) block in the inc() method. This block makes sure that only one thread can execute the return ++count at a time. The code in the synchronized block could have been more advanced, but the simple ++count suffices to get the point across. +``` -The Counter class could have been written like this instead, using a Lock instead of a synchronized block: +注意`inc()`方法中的`synchronized(this)`块,这个块每次只允许一个线程进入执行`return ++count`代码。 +Counter类可以用Lock类来实现同样的功能: + +```Java public class Counter{ private Lock lock = new Lock(); @@ -34,12 +38,14 @@ public class Counter{ return newCount; } } -The lock() method locks the Lock instance so that all threads calling lock() are blocked until unlock() is executed. +``` -Here is a simple Lock implementation: +`lock()`方法会对Lock对象进行加锁,其他的线程都会在这个方法上阻塞,执行`unlock()`方法被调用。 -public class Lock{ +下面是一个简单Lock类的实现: +```Java +public class Lock{ private boolean isLocked = false; public synchronized void lock() @@ -55,6 +61,8 @@ public class Lock{ notify(); } } +``` + Notice the while(isLocked) loop, which is also called a "spin lock". Spin locks and the methods wait() and notify() are covered in more detail in the text Thread Signaling. While isLocked is true, the thread calling lock() is parked waiting in the wait() call. In case the thread should return unexpectedly from the wait() call without having received a notify() call (AKA a Spurious Wakeup) the thread re-checks the isLocked condition to see if it is safe to proceed or not, rather than just assume that being awakened means it is safe to proceed. If isLocked is false, the thread exits the while(isLocked) loop, and sets isLocked back to true, to lock the Lock instance for other threads calling lock(). When the thread is done with the code in the critical section (the code between lock() and unlock()), the thread calls unlock(). Executing unlock() sets isLocked back to false, and notifies (awakens) one of the threads waiting in the wait() call in the lock() method, if any. From df8cce2968c56601be88295a143d954fd9499352 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 15:51:16 +0800 Subject: [PATCH 215/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 067f04f..49abb89 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -48,8 +48,7 @@ public class Counter{ public class Lock{ private boolean isLocked = false; - public synchronized void lock() - throws InterruptedException{ + public synchronized void lock() throws InterruptedException{ while(isLocked){ wait(); } From 4c639687eeec1741442c8c4cef56337026aad1cc Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 16:22:47 +0800 Subject: [PATCH 216/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 49abb89..9302431 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -62,7 +62,9 @@ public class Lock{ } ``` -Notice the while(isLocked) loop, which is also called a "spin lock". Spin locks and the methods wait() and notify() are covered in more detail in the text Thread Signaling. While isLocked is true, the thread calling lock() is parked waiting in the wait() call. In case the thread should return unexpectedly from the wait() call without having received a notify() call (AKA a Spurious Wakeup) the thread re-checks the isLocked condition to see if it is safe to proceed or not, rather than just assume that being awakened means it is safe to proceed. If isLocked is false, the thread exits the while(isLocked) loop, and sets isLocked back to true, to lock the Lock instance for other threads calling lock(). +注意`while(isLocked)`这个循环,我们称之为** 自旋锁**。自旋锁、wait方法和notify方法,我们在线程通信一文已经介绍过。当isLocked为true时,调用`lock()`方法的线程会嵌入等待状态。为了防止线程**虚假唤醒**(没调用notify()却无缘无故唤醒),将isLock作为循环的判断条件,如果线程虚假唤醒,则由于isLocked为true,则会再次调用`wait()`进入等待状态。当isLocked为false时,线程会离开while循环,将isLocked设置为true并锁住Lock对象。 + + When the thread is done with the code in the critical section (the code between lock() and unlock()), the thread calls unlock(). Executing unlock() sets isLocked back to false, and notifies (awakens) one of the threads waiting in the wait() call in the lock() method, if any. From ac99530c2de3367acf4afedaf85da2fe51903adc Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 16:31:42 +0800 Subject: [PATCH 217/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 9302431..01e7502 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -64,9 +64,8 @@ public class Lock{ 注意`while(isLocked)`这个循环,我们称之为** 自旋锁**。自旋锁、wait方法和notify方法,我们在线程通信一文已经介绍过。当isLocked为true时,调用`lock()`方法的线程会嵌入等待状态。为了防止线程**虚假唤醒**(没调用notify()却无缘无故唤醒),将isLock作为循环的判断条件,如果线程虚假唤醒,则由于isLocked为true,则会再次调用`wait()`进入等待状态。当isLocked为false时,线程会离开while循环,将isLocked设置为true并锁住Lock对象。 - - -When the thread is done with the code in the critical section (the code between lock() and unlock()), the thread calls unlock(). Executing unlock() sets isLocked back to false, and notifies (awakens) one of the threads waiting in the wait() call in the lock() method, if any. +当线程执行玩**临界区**(lock方法和unlock方法之间的代码)的代码后 +,线程调用`unlock()`方法,将isLocked设置为`false`,同时调用`notify()`方法唤醒在`lock()`方法中陷入等待的其中一个线程。 ##重得锁(Lock Reentrance) From 1aeb838a0e81a4d2842ba53b1b8b33ac76f4deb5 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 17:01:45 +0800 Subject: [PATCH 218/524] Published with https://stackedit.io/ --- ...va\344\270\255\347\232\204\351\224\201.md" | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 01e7502..7cdcbe1 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -67,12 +67,12 @@ public class Lock{ 当线程执行玩**临界区**(lock方法和unlock方法之间的代码)的代码后 ,线程调用`unlock()`方法,将isLocked设置为`false`,同时调用`notify()`方法唤醒在`lock()`方法中陷入等待的其中一个线程。 -##重得锁(Lock Reentrance) +##锁的可重入性(Lock Reentrance) -Synchronized blocks in Java are reentrant. This means, that if a Java thread enters a synchronized block of code, and thereby take the lock on the monitor object the block is synchronized on, the thread can enter other Java code blocks synchronized on the same monitor object. Here is an example: +Java中的`synchronized`块是可重入的,意思是,当一个线程进入了一个`synchronized`块并持有该监听器对象的锁后,这个线程可以进入其他的基于这个监听器对象的`synchronized`块。例如下面这个例子: +```Java public class Reentrant{ - public synchronized outer(){ inner(); } @@ -81,12 +81,14 @@ public class Reentrant{ //do something } } -Notice how both outer() and inner() are declared synchronized, which in Java is equivalent to a synchronized(this) block. If a thread calls outer() there is no problem calling inner() from inside outer(), since both methods (or blocks) are synchronized on the same monitor object ("this"). If a thread already holds the lock on a monitor object, it has access to all blocks synchronized on the same monitor object. This is called reentrance. The thread can reenter any block of code for which it already holds the lock. +``` -The lock implementation shown earlier is not reentrant. If we rewrite the Reentrant class like below, the thread calling outer() will be blocked inside the lock.lock() in the inner() method. +注意`outer()` 方法和`inner()`方法都用了**synchronized**关键字声明(等同于synchronized(this){}同步块)。如果一个线程成功进入`outer()` 方法后,也可以顺利成章地成功进入`inner()`方法,因为两个同步方法的监听器对象都是**this**对象。如果一个方法持有一个监听器对象的锁,则它可以任意进入基于这个监听器对象的同步块。这称之为**重入性**。 -public class Reentrant2{ +我们之前所实现的Lock类没不具有**可重入性**。如果我们将Reentrant类按照下面一样进行重构,调用`outer()`方法的线程将会陷入阻塞。 +```Java +public class Reentrant2{ Lock lock = new Lock(); public outer(){ @@ -101,16 +103,18 @@ public class Reentrant2{ lock.unlock(); } } -A thread calling outer() will first lock the Lock instance. Then it will call inner(). Inside the inner() method the thread will again try to lock the Lock instance. This will fail (meaning the thread will be blocked), since the Lock instance was locked already in the outer() method. +``` + +调用`outer()`方法的线程首先获得Lock实例的锁,然后调用`inner()` 方法。在`inner()`方法内部会再次调用同一个Lock实例的`lock()`方法。由于此时isLocked为true,则它将进入`while(isLocked)`内部并调`this.wait()`而进入阻塞状态。 -The reason the thread will be blocked the second time it calls lock() without having called unlock() in between, is apparent when we look at the lock() implementation: +让我们在看下Lock类的实现: +```Java public class Lock{ boolean isLocked = false; - public synchronized void lock() - throws InterruptedException{ + public synchronized void lock() throws InterruptedException{ while(isLocked){ wait(); } @@ -119,6 +123,10 @@ public class Lock{ ... } +``` + + + It is the condition inside the while loop (spin lock) that determines if a thread is allowed to exit the lock() method or not. Currently the condition is that isLocked must be false for this to be allowed, regardless of what thread locked it. To make the Lock class reentrant we need to make a small change: From 0873398e0f976a9fc26415060cfae58eb0e7e529 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 17:07:30 +0800 Subject: [PATCH 219/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 7cdcbe1..1a954b3 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -125,12 +125,11 @@ public class Lock{ } ``` +问题在于while循环的判断,当同一个线程第一次调用`lock()`方法时,isLocked为true,当它再次调用`lock()` 方法时,则会进入while循环内部并调用wait()方法而阻塞。 +为了让Lock类具有可重入性的特征,我们需要对它进行小小修改: -It is the condition inside the while loop (spin lock) that determines if a thread is allowed to exit the lock() method or not. Currently the condition is that isLocked must be false for this to be allowed, regardless of what thread locked it. - -To make the Lock class reentrant we need to make a small change: - +```Java public class Lock{ boolean isLocked = false; @@ -162,6 +161,10 @@ public class Lock{ ... } +``` + + + Notice how the while loop (spin lock) now also takes the thread that locked the Lock instance into consideration. If either the lock is unlocked (isLocked = false) or the calling thread is the thread that locked the Lock instance, the while loop will not execute, and the thread calling lock() will be allowed to exit the method. Additionally, we need to count the number of times the lock has been locked by the same thread. Otherwise, a single call to unlock() will unlock the lock, even if the lock has been locked multiple times. We don't want the lock to be unloced until the thread that locked it, has executed the same amount of unlock() calls as lock() calls. From e1100c3400c939e6ed775d063a60d0efdd71953e Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 17:08:59 +0800 Subject: [PATCH 220/524] Published with https://stackedit.io/ From 32e906600fb65ee69d88b24ecb6d29db4a634c65 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 17:09:41 +0800 Subject: [PATCH 221/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 1a954b3..5ccf894 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -83,7 +83,7 @@ public class Reentrant{ } ``` -注意`outer()` 方法和`inner()`方法都用了**synchronized**关键字声明(等同于synchronized(this){}同步块)。如果一个线程成功进入`outer()` 方法后,也可以顺利成章地成功进入`inner()`方法,因为两个同步方法的监听器对象都是**this**对象。如果一个方法持有一个监听器对象的锁,则它可以任意进入基于这个监听器对象的同步块。这称之为**重入性**。 +注意`outer()` 方法和`inner()`方法都用了 **synchronized** 关键字声明(等同于synchronized(this){}同步块)。如果一个线程成功进入`outer()` 方法后,也可以顺利成章地成功进入`inner()`方法,因为两个同步方法的监听器对象都是 **this** 对象。如果一个方法持有一个监听器对象的锁,则它可以任意进入基于这个监听器对象的同步块。这称之为**重入性**。 我们之前所实现的Lock类没不具有**可重入性**。如果我们将Reentrant类按照下面一样进行重构,调用`outer()`方法的线程将会陷入阻塞。 From b31e1d7280096b86f5a7c20674e59060f3eda377 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 17:10:15 +0800 Subject: [PATCH 222/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 5ccf894..bc95e55 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -62,7 +62,7 @@ public class Lock{ } ``` -注意`while(isLocked)`这个循环,我们称之为** 自旋锁**。自旋锁、wait方法和notify方法,我们在线程通信一文已经介绍过。当isLocked为true时,调用`lock()`方法的线程会嵌入等待状态。为了防止线程**虚假唤醒**(没调用notify()却无缘无故唤醒),将isLock作为循环的判断条件,如果线程虚假唤醒,则由于isLocked为true,则会再次调用`wait()`进入等待状态。当isLocked为false时,线程会离开while循环,将isLocked设置为true并锁住Lock对象。 +注意`while(isLocked)`这个循环,我们称之为**自旋锁**。自旋锁、wait方法和notify方法,我们在线程通信一文已经介绍过。当isLocked为true时,调用`lock()`方法的线程会嵌入等待状态。为了防止线程**虚假唤醒**(没调用notify()却无缘无故唤醒),将isLock作为循环的判断条件,如果线程虚假唤醒,则由于isLocked为true,则会再次调用`wait()`进入等待状态。当isLocked为false时,线程会离开while循环,将isLocked设置为true并锁住Lock对象。 当线程执行玩**临界区**(lock方法和unlock方法之间的代码)的代码后 ,线程调用`unlock()`方法,将isLocked设置为`false`,同时调用`notify()`方法唤醒在`lock()`方法中陷入等待的其中一个线程。 From ab83b83b2717757f521ca6b702e9633ada46a0ff Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 17:11:12 +0800 Subject: [PATCH 223/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index bc95e55..2c1c38c 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -131,13 +131,11 @@ public class Lock{ ```Java public class Lock{ - boolean isLocked = false; Thread lockedBy = null; int lockedCount = 0; - public synchronized void lock() - throws InterruptedException{ + public synchronized void lock() throws InterruptedException{ Thread callingThread = Thread.currentThread(); while(isLocked && lockedBy != callingThread){ wait(); From 36fd06778e2394fe6d44c6b8c2337031fe4203b8 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 17:22:30 +0800 Subject: [PATCH 224/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 2c1c38c..3daa78b 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -145,7 +145,6 @@ public class Lock{ lockedBy = callingThread; } - public synchronized void unlock(){ if(Thread.curentThread() == this.lockedBy){ lockedCount--; @@ -161,15 +160,13 @@ public class Lock{ } ``` +注意现在while循环添加了**当前线程是否与持有锁的线程一样**的判断。如果isLocked为false或者当前线程与持有锁的线程一样,则会绕过while循环,因此,即使连续调用两次`lock()`方法将不会再阻塞。 +除此之外,我们需要统计同一个线程调用`lock()`的次数。否则,线程线程在调用一次`unlock()`方法后将会释放锁,而不管之前调用了多少次`lock()`方法。在`unlock()`调用没有达到对应`lock()`调用的次数之前,我们不希望锁被释放。 -Notice how the while loop (spin lock) now also takes the thread that locked the Lock instance into consideration. If either the lock is unlocked (isLocked = false) or the calling thread is the thread that locked the Lock instance, the while loop will not execute, and the thread calling lock() will be allowed to exit the method. - -Additionally, we need to count the number of times the lock has been locked by the same thread. Otherwise, a single call to unlock() will unlock the lock, even if the lock has been locked multiple times. We don't want the lock to be unloced until the thread that locked it, has executed the same amount of unlock() calls as lock() calls. - -The Lock class is now reentrant. +现在,Lock类具有可重入性了。 -## 公平锁(Lock Fairness) +## 锁的公平性(Lock Fairness) Java's synchronized blocks makes no guarantees about the sequence in which threads trying to enter them are granted access. Therefore, if many threads are constantly competing for access to the same synchronized block, there is a risk that one or more of the threads are never granted access - that access is always granted to other threads. This is called starvation. To avoid this a Lock should be fair. Since the Lock implementations shown in this text uses synchronized blocks internally, they do not guarantee fairness. Starvation and fairness are discussed in more detail in the text Starvation and Fairness. From ebed3dec416d6dcd8f4310749fb90a1400010a22 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 17:29:59 +0800 Subject: [PATCH 225/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 3daa78b..c032e41 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -168,9 +168,9 @@ public class Lock{ ## 锁的公平性(Lock Fairness) -Java's synchronized blocks makes no guarantees about the sequence in which threads trying to enter them are granted access. Therefore, if many threads are constantly competing for access to the same synchronized block, there is a risk that one or more of the threads are never granted access - that access is always granted to other threads. This is called starvation. To avoid this a Lock should be fair. Since the Lock implementations shown in this text uses synchronized blocks internally, they do not guarantee fairness. Starvation and fairness are discussed in more detail in the text Starvation and Fairness. +Java的`synchronized`块并不保证进入同步块的线程顺序。因此,如果存在多个线程同时争用同一个同步块,那么将有某个或多个线程永远得不到进入同步块机会的危险。我们称之为**饥饿**。为了避免这种情况,我们需要保证锁的公平性。上面例子的Lock类是通过`synchronized`关键字实现的,在这里,它们并不能保证锁的公平性。 -Calling unlock() From a finally-clause +##在finally块中调用unlock方法(Calling unlock() From a finally-clause) When guarding a critical section with a Lock, and the critical section may throw exceptions, it is important to call the unlock() method from inside a finally-clause. Doing so makes sure that the Lock is unlocked so other threads can lock it. Here is an example: From 7994a27356be8939d797bc493e27a87ab57fd557 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 15 Sep 2014 17:31:10 +0800 Subject: [PATCH 226/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 3 +++ 1 file changed, 3 insertions(+) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index c032e41..13b6b84 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -174,10 +174,13 @@ Java的`synchronized`块并不保证进入同步块的线程顺序。因此, When guarding a critical section with a Lock, and the critical section may throw exceptions, it is important to call the unlock() method from inside a finally-clause. Doing so makes sure that the Lock is unlocked so other threads can lock it. Here is an example: +```Java lock.lock(); try{ //do critical section code, which may throw exception } finally { lock.unlock(); } +``` + This little construct makes sure that the Lock is unlocked in case an exception is thrown from the code in the critical section. If unlock() was not called from inside a finally-clause, and an exception was thrown from the critical section, the Lock would remain locked forever, causing all threads calling lock() on that Lock instance to halt indefinately. \ No newline at end of file From 5b9e1a6eb94b96b25cb546b7d79f0f8217b22ba0 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:08:12 +0800 Subject: [PATCH 227/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 13b6b84..713deba 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -1,4 +1,4 @@ -#Java中的锁 +#15.Java中的锁 **锁**跟**synchronized**的一样,是Java中的一种同步机制,但要比synchronized复杂得多。在Java 5之前,锁(以及其它更高级的线程同步机制)是由synchronized同步块的方式实现的,我们还不能完全摆脱synchronized关键字。 From c4d220de14dc02942fb677973028fc80905e1213 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:15:00 +0800 Subject: [PATCH 228/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index 713deba..c79e48e 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -10,7 +10,6 @@ ```Java public class Counter{ - private int count = 0; public int inc(){ @@ -172,7 +171,7 @@ Java的`synchronized`块并不保证进入同步块的线程顺序。因此, ##在finally块中调用unlock方法(Calling unlock() From a finally-clause) -When guarding a critical section with a Lock, and the critical section may throw exceptions, it is important to call the unlock() method from inside a finally-clause. Doing so makes sure that the Lock is unlocked so other threads can lock it. Here is an example: +当使用锁来隔离临界区时,临界区的代码有可能抛出异常,所以把`unlock()`方法放入finally块中是非常有必要的,这样做可以保证无论发生什么`unlock()`方法总可以被调用: ```Java lock.lock(); @@ -183,4 +182,5 @@ try{ } ``` + This little construct makes sure that the Lock is unlocked in case an exception is thrown from the code in the critical section. If unlock() was not called from inside a finally-clause, and an exception was thrown from the critical section, the Lock would remain locked forever, causing all threads calling lock() on that Lock instance to halt indefinately. \ No newline at end of file From 3618f7a905c287defbb63d61da45a6f2f62b494e Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:22:06 +0800 Subject: [PATCH 229/524] Published with https://stackedit.io/ --- .../15.Java\344\270\255\347\232\204\351\224\201.md" | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" index c79e48e..67667bb 100644 --- "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" @@ -182,5 +182,4 @@ try{ } ``` - -This little construct makes sure that the Lock is unlocked in case an exception is thrown from the code in the critical section. If unlock() was not called from inside a finally-clause, and an exception was thrown from the critical section, the Lock would remain locked forever, causing all threads calling lock() on that Lock instance to halt indefinately. \ No newline at end of file +这个小小的结构改变可以保证当临界区的代码抛出异常时`unlock()`总可以被调用。当临界区代码抛出异常时,如果finally块中的`unlock()`方法没有被调用,那么Lock实例将永远被锁住,调用`lock()`方法的线程将陷入无止境的阻塞状态。 \ No newline at end of file From 36311da47c8480d4805bf1a6c4b917965bdf7861 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:24:01 +0800 Subject: [PATCH 230/524] Published with https://stackedit.io/ --- ...04\350\257\273\345\206\231\351\224\201.md" | 371 ++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 "Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" diff --git "a/Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" new file mode 100644 index 0000000..a8da197 --- /dev/null +++ "b/Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -0,0 +1,371 @@ +#16.Java中的读写锁 + +A read / write lock is more sophisticated lock than the Lock implementations shown in the text Locks in Java. Imagine you have an application that reads and writes some resource, but writing it is not done as much as reading it is. Two threads reading the same resource does not cause problems for each other, so multiple threads that want to read the resource are granted access at the same time, overlapping. But, if a single thread wants to write to the resource, no other reads nor writes must be in progress at the same time. To solve this problem of allowing multiple readers but only one writer, you will need a read / write lock. + +Java 5 comes with read / write lock implementations in the java.util.concurrent package. Even so, it may still be useful to know the theory behind their implementation. + +Read / Write Lock Java Implementation + +First let's summarize the conditions for getting read and write access to the resource: + +Read Access If no threads are writing, and no threads have requested write access. +Write Access If no threads are reading or writing. +If a thread wants to read the resource, it is okay as long as no threads are writing to it, and no threads have requested write access to the resource. By up-prioritizing write-access requests we assume that write requests are more important than read-requests. Besides, if reads are what happens most often, and we did not up-prioritize writes, starvation could occur. Threads requesting write access would be blocked until all readers had unlocked the ReadWriteLock. If new threads were constantly granted read access the thread waiting for write access would remain blocked indefinately, resulting in starvation. Therefore a thread can only be granted read access if no thread has currently locked the ReadWriteLock for writing, or requested it locked for writing. + +A thread that wants write access to the resource can be granted so when no threads are reading nor writing to the resource. It doesn't matter how many threads have requested write access or in what sequence, unless you want to guarantee fairness between threads requesting write access. + +With these simple rules in mind we can implement a ReadWriteLock as shown below: + +public class ReadWriteLock{ + + private int readers = 0; + private int writers = 0; + private int writeRequests = 0; + + public synchronized void lockRead() throws InterruptedException{ + while(writers > 0 || writeRequests > 0){ + wait(); + } + readers++; + } + + public synchronized void unlockRead(){ + readers--; + notifyAll(); + } + + public synchronized void lockWrite() throws InterruptedException{ + writeRequests++; + + while(readers > 0 || writers > 0){ + wait(); + } + writeRequests--; + writers++; + } + + public synchronized void unlockWrite() throws InterruptedException{ + writers--; + notifyAll(); + } +} +The ReadWriteLock has two lock methods and two unlock methods. One lock and unlock method for read access and one lock and unlock for write access. + +The rules for read access are implemented in the lockRead() method. All threads get read access unless there is a thread with write access, or one or more threads have requested write access. + +The rules for write access are implemented in the lockWrite() method. A thread that wants write access starts out by requesting write access (writeRequests++). Then it will check if it can actually get write access. A thread can get write access if there are no threads with read access to the resource, and no threads with write access to the resource. How many threads have requested write access doesn't matter. + +It is worth noting that both unlockRead() and unlockWrite() calls notifyAll() rather than notify(). To explain why that is, imagine the following situation: + +Inside the ReadWriteLock there are threads waiting for read access, and threads waiting for write access. If a thread awakened by notify() was a read access thread, it would be put back to waiting because there are threads waiting for write access. However, none of the threads awaiting write access are awakened, so nothing more happens. No threads gain neither read nor write access. By calling noftifyAll() all waiting threads are awakened and check if they can get the desired access. + +Calling notifyAll() also has another advantage. If multiple threads are waiting for read access and none for write access, and unlockWrite() is called, all threads waiting for read access are granted read access at once - not one by one. + +Read / Write Lock Reentrance + +The ReadWriteLock class shown earlier is not reentrant. If a thread that has write access requests it again, it will block because there is already one writer - itself. Furthermore, consider this case: + +Thread 1 gets read access. + +Thread 2 requests write access but is blocked because there is one reader. + +Thread 1 re-requests read access (re-enters the lock), but is blocked because there is a write request +In this situation the previous ReadWriteLock would lock up - a situation similar to deadlock. No threads requesting neither read nor write access would be granted so. + +To make the ReadWriteLock reentrant it is necessary to make a few changes. Reentrance for readers and writers will be dealt with separately. + +Read Reentrance + +To make the ReadWriteLock reentrant for readers we will first establish the rules for read reentrance: + +A thread is granted read reentrance if it can get read access (no writers or write requests), or if it already has read access (regardless of write requests). +To determine if a thread has read access already a reference to each thread granted read access is kept in a Map along with how many times it has acquired read lock. When determing if read access can be granted this Map will be checked for a reference to the calling thread. Here is how the lockRead() and unlockRead() methods looks after that change: + +public class ReadWriteLock{ + + private Map readingThreads = + new HashMap (); + + private int writers = 0; + private int writeRequests = 0; + + public synchronized void lockRead() throws InterruptedException{ + Thread callingThread = Thread.currentThread(); + while(! canGrantReadAccess(callingThread)){ + wait(); + } + + readingThreads.put(callingThread, + (getAccessCount(callingThread) + 1)); + } + + + public synchronized void unlockRead(){ + Thread callingThread = Thread.currentThread(); + int accessCount = getAccessCount(callingThread); + if(accessCount == 1){ readingThreads.remove(callingThread); } + else { readingThreads.put(callingThread, (accessCount -1)); } + notifyAll(); + } + + + private boolean canGrantReadAccess(Thread callingThread){ + if(writers > 0) return false; + if(isReader(callingThread) return true; + if(writeRequests > 0) return false; + return true; + } + + private int getReadAccessCount(Thread callingThread){ + Integer accessCount = readingThreads.get(callingThread); + if(accessCount == null) return 0; + return accessCount.intValue(); + } + + private boolean isReader(Thread callingThread){ + return readingThreads.get(callingThread) != null; + } + +} +As you can see read reentrance is only granted if no threads are currently writing to the resource. Additionally, if the calling thread already has read access this takes precedence over any writeRequests. + +Write Reentrance + +Write reentrance is granted only if the thread has already write access. Here is how the lockWrite() and unlockWrite() methods look after that change: + +public class ReadWriteLock{ + + private Map readingThreads = + new HashMap (); + + private int writeAccesses = 0; + private int writeRequests = 0; + private Thread writingThread = null; + + public synchronized void lockWrite() throws InterruptedException{ + writeRequests++; + Thread callingThread = Thread.currentThread(); + while(! canGrantWriteAccess(callingThread)){ + wait(); + } + writeRequests--; + writeAccesses++; + writingThread = callingThread; + } + + public synchronized void unlockWrite() throws InterruptedException{ + writeAccesses--; + if(writeAccesses == 0){ + writingThread = null; + } + notifyAll(); + } + + private boolean canGrantWriteAccess(Thread callingThread){ + if(hasReaders()) return false; + if(writingThread == null) return true; + if(!isWriter(callingThread)) return false; + return true; + } + + private boolean hasReaders(){ + return readingThreads.size() > 0; + } + + private boolean isWriter(Thread callingThread){ + return writingThread == callingThread; + } +} +Notice how the thread currently holding the write lock is now taken into account when determining if the calling thread can get write access. + +Read to Write Reentrance + +Sometimes it is necessary for a thread that have read access to also obtain write access. For this to be allowed the thread must be the only reader. To achieve this the writeLock() method should be changed a bit. Here is what it would look like: + +public class ReadWriteLock{ + + private Map readingThreads = + new HashMap (); + + private int writeAccesses = 0; + private int writeRequests = 0; + private Thread writingThread = null; + + public synchronized void lockWrite() throws InterruptedException{ + writeRequests++; + Thread callingThread = Thread.currentThread(); + while(! canGrantWriteAccess(callingThread)){ + wait(); + } + writeRequests--; + writeAccesses++; + writingThread = callingThread; + } + + public synchronized void unlockWrite() throws InterruptedException{ + writeAccesses--; + if(writeAccesses == 0){ + writingThread = null; + } + notifyAll(); + } + + private boolean canGrantWriteAccess(Thread callingThread){ + if(isOnlyReader(callingThread)) return true; + if(hasReaders()) return false; + if(writingThread == null) return true; + if(!isWriter(callingThread)) return false; + return true; + } + + private boolean hasReaders(){ + return readingThreads.size() > 0; + } + + private boolean isWriter(Thread callingThread){ + return writingThread == callingThread; + } + + private boolean isOnlyReader(Thread thread){ + return readers == 1 && readingThreads.get(callingThread) != null; + } + +} +Now the ReadWriteLock class is read-to-write access reentrant. + +Write to Read Reentrance + +Sometimes a thread that has write access needs read access too. A writer should always be granted read access if requested. If a thread has write access no other threads can have read nor write access, so it is not dangerous. Here is how the canGrantReadAccess() method will look with that change: + +public class ReadWriteLock{ + + private boolean canGrantReadAccess(Thread callingThread){ + if(isWriter(callingThread)) return true; + if(writingThread != null) return false; + if(isReader(callingThread) return true; + if(writeRequests > 0) return false; + return true; + } + +} +Fully Reentrant ReadWriteLock + +Below is the fully reentran ReadWriteLock implementation. I have made a few refactorings to the access conditions to make them easier to read, and thereby easier to convince yourself that they are correct. + +public class ReadWriteLock{ + + private Map readingThreads = + new HashMap (); + + private int writeAccesses = 0; + private int writeRequests = 0; + private Thread writingThread = null; + + + public synchronized void lockRead() throws InterruptedException{ + Thread callingThread = Thread.currentThread(); + while(! canGrantReadAccess(callingThread)){ + wait(); + } + + readingThreads.put(callingThread, + (getReadAccessCount(callingThread) + 1)); + } + + private boolean canGrantReadAccess(Thread callingThread){ + if( isWriter(callingThread) ) return true; + if( hasWriter() ) return false; + if( isReader(callingThread) ) return true; + if( hasWriteRequests() ) return false; + return true; + } + + + public synchronized void unlockRead(){ + Thread callingThread = Thread.currentThread(); + if(!isReader(callingThread)){ + throw new IllegalMonitorStateException("Calling Thread does not" + + " hold a read lock on this ReadWriteLock"); + } + int accessCount = getReadAccessCount(callingThread); + if(accessCount == 1){ readingThreads.remove(callingThread); } + else { readingThreads.put(callingThread, (accessCount -1)); } + notifyAll(); + } + + public synchronized void lockWrite() throws InterruptedException{ + writeRequests++; + Thread callingThread = Thread.currentThread(); + while(! canGrantWriteAccess(callingThread)){ + wait(); + } + writeRequests--; + writeAccesses++; + writingThread = callingThread; + } + + public synchronized void unlockWrite() throws InterruptedException{ + if(!isWriter(Thread.currentThread()){ + throw new IllegalMonitorStateException("Calling Thread does not" + + " hold the write lock on this ReadWriteLock"); + } + writeAccesses--; + if(writeAccesses == 0){ + writingThread = null; + } + notifyAll(); + } + + private boolean canGrantWriteAccess(Thread callingThread){ + if(isOnlyReader(callingThread)) return true; + if(hasReaders()) return false; + if(writingThread == null) return true; + if(!isWriter(callingThread)) return false; + return true; + } + + + private int getReadAccessCount(Thread callingThread){ + Integer accessCount = readingThreads.get(callingThread); + if(accessCount == null) return 0; + return accessCount.intValue(); + } + + + private boolean hasReaders(){ + return readingThreads.size() > 0; + } + + private boolean isReader(Thread callingThread){ + return readingThreads.get(callingThread) != null; + } + + private boolean isOnlyReader(Thread callingThread){ + return readingThreads.size() == 1 && + readingThreads.get(callingThread) != null; + } + + private boolean hasWriter(){ + return writingThread != null; + } + + private boolean isWriter(Thread callingThread){ + return writingThread == callingThread; + } + + private boolean hasWriteRequests(){ + return this.writeRequests > 0; + } + +} +Calling unlock() From a finally-clause + +When guarding a critical section with a ReadWriteLock, and the critical section may throw exceptions, it is important to call the readUnlock() and writeUnlock() methods from inside a finally-clause. Doing so makes sure that the ReadWriteLock is unlocked so other threads can lock it. Here is an example: + +lock.lockWrite(); +try{ + //do critical section code, which may throw exception +} finally { + lock.unlockWrite(); +} +This little construct makes sure that the ReadWriteLock is unlocked in case an exception is thrown from the code in the critical section. If unlockWrite() was not called from inside a finally-clause, and an exception was thrown from the critical section, the ReadWriteLock would remain write locked forever, causing all threads calling lockRead() or lockWrite() on that ReadWriteLock instance to halt indefinately. The only thing that could unlock the ReadWriteLockagain would be if the ReadWriteLock is reentrant, and the thread that had it locked when the exception was thrown, later succeeds in locking it, executing the critical section and calling unlockWrite() again afterwards. That would unlock the ReadWriteLock again. But why wait for that to happen, if it happens? Calling unlockWrite() from a finally-clause is a much more robust solution. \ No newline at end of file From 1d0273e330a993faab0b2be1bae14bf959800945 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:26:06 +0800 Subject: [PATCH 231/524] Published with https://stackedit.io/ --- ...2\204\350\257\273\345\206\231\351\224\201.md" | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index a8da197..1847413 100644 --- "a/Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -1,10 +1,10 @@ -#16.Java中的读写锁 +#16.Java中的读/写锁 A read / write lock is more sophisticated lock than the Lock implementations shown in the text Locks in Java. Imagine you have an application that reads and writes some resource, but writing it is not done as much as reading it is. Two threads reading the same resource does not cause problems for each other, so multiple threads that want to read the resource are granted access at the same time, overlapping. But, if a single thread wants to write to the resource, no other reads nor writes must be in progress at the same time. To solve this problem of allowing multiple readers but only one writer, you will need a read / write lock. Java 5 comes with read / write lock implementations in the java.util.concurrent package. Even so, it may still be useful to know the theory behind their implementation. -Read / Write Lock Java Implementation +##Read / Write Lock Java Implementation First let's summarize the conditions for getting read and write access to the resource: @@ -61,7 +61,7 @@ Inside the ReadWriteLock there are threads waiting for read access, and threads Calling notifyAll() also has another advantage. If multiple threads are waiting for read access and none for write access, and unlockWrite() is called, all threads waiting for read access are granted read access at once - not one by one. -Read / Write Lock Reentrance +##Read / Write Lock Reentrance The ReadWriteLock class shown earlier is not reentrant. If a thread that has write access requests it again, it will block because there is already one writer - itself. Furthermore, consider this case: @@ -129,7 +129,7 @@ public class ReadWriteLock{ } As you can see read reentrance is only granted if no threads are currently writing to the resource. Additionally, if the calling thread already has read access this takes precedence over any writeRequests. -Write Reentrance +##Write Reentrance Write reentrance is granted only if the thread has already write access. Here is how the lockWrite() and unlockWrite() methods look after that change: @@ -178,7 +178,7 @@ public class ReadWriteLock{ } Notice how the thread currently holding the write lock is now taken into account when determining if the calling thread can get write access. -Read to Write Reentrance +##Read to Write Reentrance Sometimes it is necessary for a thread that have read access to also obtain write access. For this to be allowed the thread must be the only reader. To achieve this the writeLock() method should be changed a bit. Here is what it would look like: @@ -248,7 +248,8 @@ public class ReadWriteLock{ } } -Fully Reentrant ReadWriteLock + +##Fully Reentrant ReadWriteLock Below is the fully reentran ReadWriteLock implementation. I have made a few refactorings to the access conditions to make them easier to read, and thereby easier to convince yourself that they are correct. @@ -358,7 +359,8 @@ public class ReadWriteLock{ } } -Calling unlock() From a finally-clause + +##Calling unlock() From a finally-clause When guarding a critical section with a ReadWriteLock, and the critical section may throw exceptions, it is important to call the readUnlock() and writeUnlock() methods from inside a finally-clause. Doing so makes sure that the ReadWriteLock is unlocked so other threads can lock it. Here is an example: From 538b5bcb4d1c91d145db6f300a89da15877a3311 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:31:46 +0800 Subject: [PATCH 232/524] Published with https://stackedit.io/ --- ...15\345\205\245\351\224\201\346\255\273.md" | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 "Java-Concurrency/17.\351\207\215\345\205\245\351\224\201\346\255\273.md" diff --git "a/Java-Concurrency/17.\351\207\215\345\205\245\351\224\201\346\255\273.md" "b/Java-Concurrency/17.\351\207\215\345\205\245\351\224\201\346\255\273.md" new file mode 100644 index 0000000..ff5a4c3 --- /dev/null +++ "b/Java-Concurrency/17.\351\207\215\345\205\245\351\224\201\346\255\273.md" @@ -0,0 +1,44 @@ +#17.重入锁死 + +Reentrance lockout is a situation similar to deadlock and nested monitor lockout. Reentrance lockout is also covered in part in the texts on Locks and Read / Write Locks. + +Reentrance lockout may occur if a thread reenters a Lock, ReadWriteLock or some other synchronizer that is not reentrant. Reentrant means that a thread that already holds a lock can retake it. Java's synchronized blocks are reentrant. Therefore the following code will work without problems: + +public class Reentrant{ + + public synchronized outer(){ + inner(); + } + + public synchronized inner(){ + //do something + } +} +Notice how both outer() and inner() are declared synchronized, which in Java is equivalent to a synchronized(this) block. If a thread calls outer() there is no problem calling inner() from inside outer(), since both methods (or blocks) are synchronized on the same monitor object ("this"). If a thread already holds the lock on a monitor object, it has access to all blocks synchronized on the same monitor object. This is called reentrance. The thread can reenter any block of code for which it already holds the lock. + +The following Lock implementation is not reentrant: + +public class Lock{ + + private boolean isLocked = false; + + public synchronized void lock() + throws InterruptedException{ + while(isLocked){ + wait(); + } + isLocked = true; + } + + public synchronized void unlock(){ + isLocked = false; + notify(); + } +} +If a thread calls lock() twice without calling unlock() in between, the second call to lock() will block. A reentrance lockout has occurred. + +To avoid reentrance lockouts you have two options: + +Avoid writing code that reenters locks +Use reentrant locks +Which of these options suit your project best depends on your concrete situation. Reentrant locks often don't perform as well as non-reentrant locks, and they are harder to implement, but this may not necessary be a problem in your case. Whether or not your code is easier to implement with or without lock reentrance must be determined case by case. \ No newline at end of file From c2c823b96c8862f0def4a1b5f9d38b8c991332b1 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:36:21 +0800 Subject: [PATCH 233/524] =?UTF-8?q?Update=2008.Java=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E5=9D=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...va\345\220\214\346\255\245\345\235\227.md" | 139 ++++++++++-------- 1 file changed, 77 insertions(+), 62 deletions(-) diff --git "a/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" "b/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" index 40668d6..dfbacd1 100644 --- "a/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" +++ "b/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" @@ -1,3 +1,18 @@ +Skip to content + This repository +Explore +Gist +Blog +Help +cokepluscarbon cokepluscarbon + +1 Unwatch + Star 0 + Fork 1cokepluscarbon/Java + branch: master Java / Java-Concurrency / 08.Java同步块 +cokepluscarboncokepluscarbon 3 days ago rename directory +1 contributor +184 lines (126 sloc) 7.719 kb RawBlameHistory #08.Java同步块 A Java synchronized block marks a method or a block of code as synchronized. Java synchronized blocks can be used to avoid race conditions. @@ -20,7 +35,7 @@ Java中的同步块使用关键字**synchronized**进行标记**。同步块在J ##同步实例方法(Synchronized Instance Methods) -Here is a synchronized instance method: +下面是一个同步的实例方法: ```Java public synchronized void add(int value){ @@ -28,13 +43,13 @@ Here is a synchronized instance method: } ``` -Notice the use of the synchronized keyword in the method declaration. This tells Java that the method is synchronized. +使用**synchronized**关键字对方法进行声明,告诉JVM这是一个同步的方法。 -A synchronized instance method in Java is synchronized on the instance (object) owning the method. Thus, each instance has its synchronized methods synchronized on a different object: the owning instance. Only one thread can execute inside a synchronized instance method. If more than one instance exist, then one thread at a time can execute inside a synchronized instance method per instance. One thread per instance. +Java中的**同步实例方法是基于这个方法所属的实例对象上进行同步的**。因此,每一个同步实例方法都是基于各自的实例对象进行同步的。同一时间,只有一个线程可以访问一个实例对象的同步实例方法。如果有多个实例存在,那么每个线程都可以同时访问各自不同实例对象的同步实例方法,一个实例对象对应一个线程。 ##同步静态方法(Synchronized Static Methods) -Static methods are marked as synchronized just like instance methods using the synchronized keyword. Here is a Java synchronized static method example: +静态方法的同步与实例方法一致,都是使用**synchronized**在方法放进行声明。 ```Java public static synchronized void add(int value){ @@ -42,17 +57,17 @@ Static methods are marked as synchronized just like instance methods using the s } ``` -Also here the synchronized keyword tells Java that the method is synchronized. +同样的,这里的**synchronized**关键字用于告诉JVM这个静态方法是同步的。 -Synchronized static methods are synchronized on the class object of the class the synchronized static method belongs to. Since only one class object exists in the Java VM per class, only one thread can execute inside a static synchronized method in the same class. +**同步静态方法是基于这个静态方法所属的类对象进行同步的**。由于在JVM中,每个类有且只有一个类对象,因此,在同一时间内,只有一个线程能够访问同一个类的同步静态方法。 -If the static synchronized methods are located in different classes, then one thread can execute inside the static synchronized methods of each class. One thread per class regardless of which static synchronized method it calls. +如果同步静态方法位于不同的类中,那么每个线程都可以访问各自对应的类的同步静态方法,一个线程对应一个类。 ##实例方法中的同步块(Synchronized Blocks in Instance Methods) -You do not have to synchronize a whole method. Sometimes it is preferable to synchronize only part of a method. Java synchronized blocks inside methods makes this possible. +有些时候,你并不需要同步整一个方法,而只需要同步这个方法下的一小部分代码块。你可以在方法里面使用同步代码块。 -Here is a synchronized block of Java code inside an unsynchronized Java method: +下面这个例子就是在非同步方法里面使用了同步代码块: ```Java public void add(int value){ @@ -63,13 +78,13 @@ Here is a synchronized block of Java code inside an unsynchronized Java method: } ``` -This example uses the Java synchronized block construct to mark a block of code as synchronized. This code will now execute as if it was a synchronized method. +这个例子里,用了Java的同步代码块来使代码进行同步,让这个方法像同步方法一样执行。 -Notice how the Java synchronized block construct takes an object in parentheses. In the example "this" is used, which is the instance the add method is called on. The object taken in the parentheses by the synchronized construct is called a monitor object. The code is said to be synchronized on the monitor object. A synchronized instance method uses the object it belongs to as monitor object. +注意在Java的同步代码块里,需要在括号里传递一个对象。这个例子中,这个对象是**this**,this指的是这个实例对象本身。在Java同步代码块括号中的对象称为**监听器对象**。意味着,这个同步块是基于这个监听器对象进行同步的。同步实例方法使用其所在实例对象作为监听器对象。 -Only one thread can execute inside a Java code block synchronized on the same monitor object. +**同一时间,只有一个线程能够访问基于同一个监听器对象的同步代码。** -The following two examples are both synchronized on the instance they are called on. They are therefore equivalent with respect to synchronization: +下面这个例子,两个同步代码都是基于同一个实例对象进行同步的: ```Java public class MyClass { @@ -89,13 +104,13 @@ The following two examples are both synchronized on the instance they are called } ``` -Thus only a single thread can execute inside either of the two synchronized blocks in this example. +因此,在这个例子中,每次仅能有一个线程能够访问这两个同步代码的任意一个同步代码。 -Had the second synchronized block been synchronized on a different object than this, then one thread at a time had been able to execute inside each method. +如果第二个同步块是基于其他监听器对象,例如`synchronized (this.getClass()) {}`,则此时第一个和第二个同步代码的监听器对象分别为:当前实例对象和当前类对象。因此,这两个同步代码可以同时由不同的线程进行访问。 ##静态方法中的同步块(Synchronized Blocks in Static Methods) -Here are the same two examples as static methods. These methods are synchronized on the class object of the class the methods belong to: +下面这个例子中,两个同步代码都是基于当前的类对象进行同步的: ```Java public class MyClass { @@ -115,48 +130,47 @@ Here are the same two examples as static methods. These methods are synchronized } ``` -Only one thread can execute inside any of these two methods at the same time. +同一时间,只有一个线程能够访问这两个同步代码的任意一个同步代码。 + +如果第二个方法的监听器对象非MyClass.class对象,则两个同步代码可以同时被两个线程访问。 -Had the second synchronized block been synchronized on a different object than MyClass.class, then one thread could execute inside each method at the same time. ##Java同步示例(Java Synchronized Example) Here is an example that starts 2 threads and have both of them call the add method on the same instance of Counter. Only one thread at a time will be able to call the add method on the same instance, because the method is synchronized on the instance it belongs to. ```Java - public class Counter{ - - long count = 0; - - public synchronized void add(long value){ - this.count += value; - } - } - public class CounterThread extends Thread{ - - protected Counter counter = null; - - public CounterThread(Counter counter){ - this.counter = counter; - } - - public void run() { - for(int i=0; i<10; i++){ - counter.add(i); - } - } - } - public class Example { - - public static void main(String[] args){ - Counter counter = new Counter(); - Thread threadA = new CounterThread(counter); - Thread threadB = new CounterThread(counter); - - threadA.start(); - threadB.start(); - } +public class Counter{ + long count = 0; + + public synchronized void add(long value){ + this.count += value; + } +} +public class CounterThread extends Thread{ + protected Counter counter = null; + + public CounterThread(Counter counter){ + this.counter = counter; + } + + public void run() { +for(int i=0; i<10; i++){ + counter.add(i); + } + } +} +public class Example { + + public static void main(String[] args){ + Counter counter = new Counter(); + Thread threadA = new CounterThread(counter); + Thread threadB = new CounterThread(counter); + + threadA.start(); + threadB.start(); } +} ``` Two threads are created. The same Counter instance is passed to both of them in their constructor. The Counter.add() method is synchronized on the instance, because the add method is an instance method, and marked as synchronized. Therefore only one of the threads can call the add() method at a time. The other thread will wait until the first thread leaves the add() method, before it can execute the method itself. @@ -164,22 +178,23 @@ Two threads are created. The same Counter instance is passed to both of them in If the two threads had referenced two separate Counter instances, there would have been no problems calling the add() methods simultaneously. The calls would have been to different objects, so the methods called would also be synchronized on different objects (the object owning the method). Therefore the calls would not block. Here is how that could look: ```Java - public class Example { - - public static void main(String[] args){ - Counter counterA = new Counter(); - Counter counterB = new Counter(); - Thread threadA = new CounterThread(counterA); - Thread threadB = new CounterThread(counterB); - - threadA.start(); - threadB.start(); - } +public class Example { + public static void main(String[] args){ + Counter counterA = new Counter(); + Counter counterB = new Counter(); + Thread threadA = new CounterThread(counterA); + Thread threadB = new CounterThread(counterB); + + threadA.start(); + threadB.start(); } +} ``` Notice how the two threads, threadA and threadB, no longer reference the same counter instance. The add method of counterA and counterB are synchronized on their two owning instances. Calling add() on counterA will thus not block a call to add() on counterB. ##Java Concurrency Utilities -The synchronized mechanism was Java's first mechanism for synchronizing access to objects shared by multiple threads. The synchronized mechanism isn't very advanced though. That is why Java 5 got a whole set of concurrency utility classes to help developers implement more fine grained concurrency control than what you get with synchronized. \ No newline at end of file +`synchronized`机制是Java第一个引进的用于同步多线程资源共享的机制。然而`synchroniez`机制并不高效。这就是为什么Java 5提供了一整套的并发工具类,以帮助开发人员实现更细粒度的并发控制 +。 +Status API Training Shop Blog About © 2014 GitHub, Inc. Terms Privacy Security Contact From 8252a3dc0637cd18a6e35b89ed2f4d180f6d9539 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:36:57 +0800 Subject: [PATCH 234/524] =?UTF-8?q?Update=2008.Java=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E5=9D=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...8.Java\345\220\214\346\255\245\345\235\227.md" | 15 --------------- 1 file changed, 15 deletions(-) diff --git "a/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" "b/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" index dfbacd1..109ff28 100644 --- "a/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" +++ "b/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" @@ -1,18 +1,3 @@ -Skip to content - This repository -Explore -Gist -Blog -Help -cokepluscarbon cokepluscarbon - -1 Unwatch - Star 0 - Fork 1cokepluscarbon/Java - branch: master Java / Java-Concurrency / 08.Java同步块 -cokepluscarboncokepluscarbon 3 days ago rename directory -1 contributor -184 lines (126 sloc) 7.719 kb RawBlameHistory #08.Java同步块 A Java synchronized block marks a method or a block of code as synchronized. Java synchronized blocks can be used to avoid race conditions. From 3c022105a2e3c20d8702b000f7d45b38b6f5b305 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:37:28 +0800 Subject: [PATCH 235/524] =?UTF-8?q?Update=2008.Java=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E5=9D=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../08.Java\345\220\214\346\255\245\345\235\227.md" | 2 -- 1 file changed, 2 deletions(-) diff --git "a/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" "b/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" index 109ff28..9ab49f6 100644 --- "a/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" +++ "b/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227.md" @@ -1,7 +1,5 @@ #08.Java同步块 -A Java synchronized block marks a method or a block of code as synchronized. Java synchronized blocks can be used to avoid race conditions. - Java synchronized block(Java同步块)用来对方法或代码块进行标记,表明这个方法或代码块是同步的。Java同步块可以避免**竞态条件**。 From 06f398ba2a85c2e75a422052d9dcd20f085d11ec Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:37:48 +0800 Subject: [PATCH 236/524] =?UTF-8?q?Delete=2008.Java=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ....Java\345\220\214\346\255\245\345\235\227" | 184 ------------------ 1 file changed, 184 deletions(-) delete mode 100644 "Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227" diff --git "a/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227" "b/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227" deleted file mode 100644 index 9edb617..0000000 --- "a/Java-Concurrency/08.Java\345\220\214\346\255\245\345\235\227" +++ /dev/null @@ -1,184 +0,0 @@ -#08.Java同步块 - -A Java synchronized block marks a method or a block of code as synchronized. Java synchronized blocks can be used to avoid race conditions. - -Java synchronized block(Java同步块)用来对方法或代码块进行标记,表明这个方法或代码块是同步的。Java同步块可以避免**竞态条件**。 - - -##synchronized关键字(The Java synchronized Keyword) - -Java中的同步块使用关键字**synchronized**进行标记**。同步块在Java中是同步在某个对象上。所有同步在一个对象上的同步块在同一时间只能被一个线程进入并执行里面的代码。**其他所有试图进入该对象同步块的线程将被阻塞,直到执行该同步块中的线程退出。 - -**synchronized**关键字可以被用于标记以下四种不同类型的块: - -- 实例方法(Instance methods) -- 静态方法(Static methods) -- 实例方法中的代码块(Code blocks inside instance methods) -- 静态方法中的代码块(Code blocks inside static methods) - -上述同步块都同步在不同对象上。实际需要那种同步块视具体情况而定。 - -##同步实例方法(Synchronized Instance Methods) - -下面是一个同步的实例方法: - -```Java - public synchronized void add(int value){ - this.count += value; - } -``` - -使用**synchronized**关键字对方法进行声明,告诉JVM这是一个同步的方法。 - -Java中的**同步实例方法是基于这个方法所属的实例对象上进行同步的**。因此,每一个同步实例方法都是基于各自的实例对象进行同步的。同一时间,只有一个线程可以访问一个实例对象的同步实例方法。如果有多个实例存在,那么每个线程都可以同时访问各自不同实例对象的同步实例方法,一个实例对象对应一个线程。 - -##同步静态方法(Synchronized Static Methods) - -静态方法的同步与实例方法一致,都是使用**synchronized**在方法放进行声明。 - -```Java - public static synchronized void add(int value){ - count += value; - } -``` - -同样的,这里的**synchronized**关键字用于告诉JVM这个静态方法是同步的。 - -**同步静态方法是基于这个静态方法所属的类对象进行同步的**。由于在JVM中,每个类有且只有一个类对象,因此,在同一时间内,只有一个线程能够访问同一个类的同步静态方法。 - -如果同步静态方法位于不同的类中,那么每个线程都可以访问各自对应的类的同步静态方法,一个线程对应一个类。 - -##实例方法中的同步块(Synchronized Blocks in Instance Methods) - -有些时候,你并不需要同步整一个方法,而只需要同步这个方法下的一小部分代码块。你可以在方法里面使用同步代码块。 - -下面这个例子就是在非同步方法里面使用了同步代码块: - -```Java - public void add(int value){ - - synchronized(this){ - this.count += value; - } - } -``` - -这个例子里,用了Java的同步代码块来使代码进行同步,让这个方法像同步方法一样执行。 - -注意在Java的同步代码块里,需要在括号里传递一个对象。这个例子中,这个对象是**this**,this指的是这个实例对象本身。在Java同步代码块括号中的对象称为**监听器对象**。意味着,这个同步块是基于这个监听器对象进行同步的。同步实例方法使用其所在实例对象作为监听器对象。 - -**同一时间,只有一个线程能够访问基于同一个监听器对象的同步代码。** - -下面这个例子,两个同步代码都是基于同一个实例对象进行同步的: - -```Java - public class MyClass { - - public synchronized void log1(String msg1, String msg2){ - log.writeln(msg1); - log.writeln(msg2); - } - - - public void log2(String msg1, String msg2){ - synchronized(this){ - log.writeln(msg1); - log.writeln(msg2); - } - } - } -``` - -因此,在这个例子中,每次仅能有一个线程能够访问这两个同步代码的任意一个同步代码。 - -如果第二个同步块是基于其他监听器对象,例如`synchronized (this.getClass()) {}`,则此时第一个和第二个同步代码的监听器对象分别为:当前实例对象和当前类对象。因此,这两个同步代码可以同时由不同的线程进行访问。 - -##静态方法中的同步块(Synchronized Blocks in Static Methods) - -下面这个例子中,两个同步代码都是基于当前的类对象进行同步的: - -```Java - public class MyClass { - - public static synchronized void log1(String msg1, String msg2){ - log.writeln(msg1); - log.writeln(msg2); - } - - - public static void log2(String msg1, String msg2){ - synchronized(MyClass.class){ - log.writeln(msg1); - log.writeln(msg2); - } - } - } -``` - -同一时间,只有一个线程能够访问这两个同步代码的任意一个同步代码。 - -如果第二个方法的监听器对象非MyClass.class对象,则两个同步代码可以同时被两个线程访问。 - - -##Java同步示例(Java Synchronized Example) - -Here is an example that starts 2 threads and have both of them call the add method on the same instance of Counter. Only one thread at a time will be able to call the add method on the same instance, because the method is synchronized on the instance it belongs to. - -```Java -public class Counter{ - long count = 0; - - public synchronized void add(long value){ - this.count += value; - } -} -public class CounterThread extends Thread{ - protected Counter counter = null; - - public CounterThread(Counter counter){ - this.counter = counter; - } - - public void run() { -for(int i=0; i<10; i++){ - counter.add(i); - } - } -} -public class Example { - - public static void main(String[] args){ - Counter counter = new Counter(); - Thread threadA = new CounterThread(counter); - Thread threadB = new CounterThread(counter); - - threadA.start(); - threadB.start(); - } -} -``` - -Two threads are created. The same Counter instance is passed to both of them in their constructor. The Counter.add() method is synchronized on the instance, because the add method is an instance method, and marked as synchronized. Therefore only one of the threads can call the add() method at a time. The other thread will wait until the first thread leaves the add() method, before it can execute the method itself. - -If the two threads had referenced two separate Counter instances, there would have been no problems calling the add() methods simultaneously. The calls would have been to different objects, so the methods called would also be synchronized on different objects (the object owning the method). Therefore the calls would not block. Here is how that could look: - -```Java -public class Example { - public static void main(String[] args){ - Counter counterA = new Counter(); - Counter counterB = new Counter(); - Thread threadA = new CounterThread(counterA); - Thread threadB = new CounterThread(counterB); - - threadA.start(); - threadB.start(); - } -} -``` - -Notice how the two threads, threadA and threadB, no longer reference the same counter instance. The add method of counterA and counterB are synchronized on their two owning instances. Calling add() on counterA will thus not block a call to add() on counterB. - -##Java Concurrency Utilities - -`synchronized`机制是Java第一个引进的用于同步多线程资源共享的机制。然而`synchroniez`机制并不高效。这就是为什么Java 5提供了一整套的并发工具类,以帮助开发人员实现更细粒度的并发控制 -。 \ No newline at end of file From 696b9ee88037abe8e99a097748a474c89624eeb6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:39:58 +0800 Subject: [PATCH 237/524] Published with https://stackedit.io/ --- ...le\345\205\263\351\224\256\345\255\227.md" | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 "Java-Concurrency/9.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" diff --git "a/Java-Concurrency/9.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/9.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" new file mode 100644 index 0000000..67de7c1 --- /dev/null +++ "b/Java-Concurrency/9.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -0,0 +1,136 @@ +#19.信号量 + +A Semaphore is a thread synchronization construct that can be used either to send signals between threads to avoid missed signals, or to guard a critical section like you would with a lock. Java 5 comes with semaphore implementations in the java.util.concurrent package so you don't have to implement your own semaphores. Still, it can be useful to know the theory behind their implementation and use. + +Java 5 comes with a built-in Semaphore so you don't have to implement your own. You can read more about it in the java.util.concurrent.Semaphore text, in my java.util.concurrent tutorial. + +Simple Semaphore + +Here is a simple Semaphore implementation: + +public class Semaphore { + private boolean signal = false; + + public synchronized void take() { + this.signal = true; + this.notify(); + } + + public synchronized void release() throws InterruptedException{ + while(!this.signal) wait(); + this.signal = false; + } + +} +The take() method sends a signal which is stored internally in the Semaphore. The release() method waits for a signal. When received the signal flag is cleared again, and the release() method exited. + +Using a semaphore like this you can avoid missed signals. You will call take() instead of notify() and release() instead of wait(). If the call to take() happens before the call to release() the thread calling release() will still know that take() was called, because the signal is stored internally in the signal variable. This is not the case with wait() and notify(). + +The names take() and release() may seem a bit odd when using a semaphore for signaling. The names origin from the use of semaphores as locks, as explained later in this text. In that case the names make more sense. + +Using Semaphores for Signaling + +Here is a simplified example of two threads signaling each other using a Semaphore: + +Semaphore semaphore = new Semaphore(); + +SendingThread sender = new SendingThread(semaphore); + +ReceivingThread receiver = new ReceivingThread(semaphore); + +receiver.start(); +sender.start(); +public class SendingThread { + Semaphore semaphore = null; + + public SendingThread(Semaphore semaphore){ + this.semaphore = semaphore; + } + + public void run(){ + while(true){ + //do something, then signal + this.semaphore.take(); + + } + } +} +public class RecevingThread { + Semaphore semaphore = null; + + public ReceivingThread(Semaphore semaphore){ + this.semaphore = semaphore; + } + + public void run(){ + while(true){ + this.semaphore.release(); + //receive signal, then do something... + } + } +} +Counting Semaphore + +The Semaphore implementation in the previous section does not count the number of signals sent to it by take() method calls. We can change the Semaphore to do so. This is called a counting semaphore. Here is a simple implementation of a counting semaphore: + +public class CountingSemaphore { + private int signals = 0; + + public synchronized void take() { + this.signals++; + this.notify(); + } + + public synchronized void release() throws InterruptedException{ + while(this.signals == 0) wait(); + this.signals--; + } + +} +Bounded Semaphore + +The CoutingSemaphore has no upper bound on how many signals it can store. We can change the semaphore implementation to have an upper bound, like this: + +public class BoundedSemaphore { + private int signals = 0; + private int bound = 0; + + public BoundedSemaphore(int upperBound){ + this.bound = upperBound; + } + + public synchronized void take() throws InterruptedException{ + while(this.signals == bound) wait(); + this.signals++; + this.notify(); + } + + public synchronized void release() throws InterruptedException{ + while(this.signals == 0) wait(); + this.signals--; + this.notify(); + } +} +Notice how the take() method now blocks if the number of signals is equal to the upper bound. Not until a thread has called release() will the thread calling take() be allowed to deliver its signal, if the BoundedSemaphore has reached its upper signal limit. + +Using Semaphores as Locks + +It is possible to use a bounded semaphore as a lock. To do so, set the upper bound to 1, and have the call to take() and release() guard the critical section. Here is an example: + +BoundedSemaphore semaphore = new BoundedSemaphore(1); + +... + +semaphore.take(); + +try{ + //critical section +} finally { + semaphore.release(); +} +In contrast to the signaling use case the methods take() and release() are now called by the same thread. Since only one thread is allowed to take the semaphore, all other threads calling take() will be blocked until release() is called. The call to release() will never block since there has always been a call to take() first. + +You can also use a bounded semaphore to limit the number of threads allowed into a section of code. For instance, in the example above, what would happen if you set the limit of the BoundedSemaphore to 5? 5 threads would be allowed to enter the critical section at a time. You would have to make sure though, that the thread operations do not conflict for these 5 threads, or you application will fail. + +The relase() method is called from inside a finally-block to make sure it is called even if an exception is thrown from the critical section. + From cc5ff57aad8b93f963a4b7894be0ced44bc22660 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:43:00 +0800 Subject: [PATCH 238/524] rename --- .../10.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 0 .../11.\346\255\273\351\224\201.md" | 0 .../12.\351\242\204\351\230\262\346\255\273\351\224\201.md" | 0 ...51\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" | 0 ...45\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" | 0 .../{14.Slipped Conditions.md => 15.Slipped Conditions.md} | 0 .../16.Java\344\270\255\347\232\204\351\224\201.md" | 0 ...44\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 0 .../18.\351\207\215\345\205\245\351\224\201\346\255\273.md" | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename "Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" => "Java-Concurrency/10.\347\272\277\347\250\213\351\200\232\344\277\241.md" (100%) rename "Java-Concurrency/10.\346\255\273\351\224\201.md" => "Java-Concurrency/11.\346\255\273\351\224\201.md" (100%) rename "Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" => "Java-Concurrency/12.\351\242\204\351\230\262\346\255\273\351\224\201.md" (100%) rename "Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" => "Java-Concurrency/13.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" (100%) rename "Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" => "Java-Concurrency/14.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" (100%) rename Java-Concurrency/{14.Slipped Conditions.md => 15.Slipped Conditions.md} (100%) rename "Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" => "Java-Concurrency/16.Java\344\270\255\347\232\204\351\224\201.md" (100%) rename "Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" => "Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" (100%) rename "Java-Concurrency/17.\351\207\215\345\205\245\351\224\201\346\255\273.md" => "Java-Concurrency/18.\351\207\215\345\205\245\351\224\201\346\255\273.md" (100%) diff --git "a/Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency/10.\347\272\277\347\250\213\351\200\232\344\277\241.md" similarity index 100% rename from "Java-Concurrency/09.\347\272\277\347\250\213\351\200\232\344\277\241.md" rename to "Java-Concurrency/10.\347\272\277\347\250\213\351\200\232\344\277\241.md" diff --git "a/Java-Concurrency/10.\346\255\273\351\224\201.md" "b/Java-Concurrency/11.\346\255\273\351\224\201.md" similarity index 100% rename from "Java-Concurrency/10.\346\255\273\351\224\201.md" rename to "Java-Concurrency/11.\346\255\273\351\224\201.md" diff --git "a/Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" "b/Java-Concurrency/12.\351\242\204\351\230\262\346\255\273\351\224\201.md" similarity index 100% rename from "Java-Concurrency/11.\351\242\204\351\230\262\346\255\273\351\224\201.md" rename to "Java-Concurrency/12.\351\242\204\351\230\262\346\255\273\351\224\201.md" diff --git "a/Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/13.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" similarity index 100% rename from "Java-Concurrency/12.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" rename to "Java-Concurrency/13.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" diff --git "a/Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" "b/Java-Concurrency/14.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" similarity index 100% rename from "Java-Concurrency/13.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" rename to "Java-Concurrency/14.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" diff --git a/Java-Concurrency/14.Slipped Conditions.md b/Java-Concurrency/15.Slipped Conditions.md similarity index 100% rename from Java-Concurrency/14.Slipped Conditions.md rename to Java-Concurrency/15.Slipped Conditions.md diff --git "a/Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/16.Java\344\270\255\347\232\204\351\224\201.md" similarity index 100% rename from "Java-Concurrency/15.Java\344\270\255\347\232\204\351\224\201.md" rename to "Java-Concurrency/16.Java\344\270\255\347\232\204\351\224\201.md" diff --git "a/Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" similarity index 100% rename from "Java-Concurrency/16.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" rename to "Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" diff --git "a/Java-Concurrency/17.\351\207\215\345\205\245\351\224\201\346\255\273.md" "b/Java-Concurrency/18.\351\207\215\345\205\245\351\224\201\346\255\273.md" similarity index 100% rename from "Java-Concurrency/17.\351\207\215\345\205\245\351\224\201\346\255\273.md" rename to "Java-Concurrency/18.\351\207\215\345\205\245\351\224\201\346\255\273.md" From d60ea9586310be743dc35654f12257158f481d79 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:44:21 +0800 Subject: [PATCH 239/524] rename --- ...55\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "Java-Concurrency/9.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" => "Java-Concurrency/09.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" (100%) diff --git "a/Java-Concurrency/9.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" similarity index 100% rename from "Java-Concurrency/9.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" rename to "Java-Concurrency/09.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" From f0e060bca92f9a12d2d30a497d83da9b1891437d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:50:21 +0800 Subject: [PATCH 240/524] Published with https://stackedit.io/ --- ...9.\344\277\241\345\217\267\351\207\217.md" | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 "Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" new file mode 100644 index 0000000..3605de7 --- /dev/null +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -0,0 +1,138 @@ +19.信号量 + +A Semaphore is a thread synchronization construct that can be used either to send signals between threads to avoid missed signals, or to guard a critical section like you would with a lock. Java 5 comes with semaphore implementations in the java.util.concurrent package so you don't have to implement your own semaphores. Still, it can be useful to know the theory behind their implementation and use. + +Java 5 comes with a built-in Semaphore so you don't have to implement your own. You can read more about it in the java.util.concurrent.Semaphore text, in my java.util.concurrent tutorial. + +##Simple Semaphore + +Here is a simple Semaphore implementation: + +public class Semaphore { + private boolean signal = false; + + public synchronized void take() { + this.signal = true; + this.notify(); + } + + public synchronized void release() throws InterruptedException{ + while(!this.signal) wait(); + this.signal = false; + } + +} +The take() method sends a signal which is stored internally in the Semaphore. The release() method waits for a signal. When received the signal flag is cleared again, and the release() method exited. + +Using a semaphore like this you can avoid missed signals. You will call take() instead of notify() and release() instead of wait(). If the call to take() happens before the call to release() the thread calling release() will still know that take() was called, because the signal is stored internally in the signal variable. This is not the case with wait() and notify(). + +The names take() and release() may seem a bit odd when using a semaphore for signaling. The names origin from the use of semaphores as locks, as explained later in this text. In that case the names make more sense. + +##Using Semaphores for Signaling + +Here is a simplified example of two threads signaling each other using a Semaphore: + +Semaphore semaphore = new Semaphore(); + +SendingThread sender = new SendingThread(semaphore); + +ReceivingThread receiver = new ReceivingThread(semaphore); + +receiver.start(); +sender.start(); +public class SendingThread { + Semaphore semaphore = null; + + public SendingThread(Semaphore semaphore){ + this.semaphore = semaphore; + } + + public void run(){ + while(true){ + //do something, then signal + this.semaphore.take(); + + } + } +} +public class RecevingThread { + Semaphore semaphore = null; + + public ReceivingThread(Semaphore semaphore){ + this.semaphore = semaphore; + } + + public void run(){ + while(true){ + this.semaphore.release(); + //receive signal, then do something... + } + } +} + +##Counting Semaphore + +The Semaphore implementation in the previous section does not count the number of signals sent to it by take() method calls. We can change the Semaphore to do so. This is called a counting semaphore. Here is a simple implementation of a counting semaphore: + +public class CountingSemaphore { + private int signals = 0; + + public synchronized void take() { + this.signals++; + this.notify(); + } + + public synchronized void release() throws InterruptedException{ + while(this.signals == 0) wait(); + this.signals--; + } + +} + +##Bounded Semaphore + +The CoutingSemaphore has no upper bound on how many signals it can store. We can change the semaphore implementation to have an upper bound, like this: + +public class BoundedSemaphore { + private int signals = 0; + private int bound = 0; + + public BoundedSemaphore(int upperBound){ + this.bound = upperBound; + } + + public synchronized void take() throws InterruptedException{ + while(this.signals == bound) wait(); + this.signals++; + this.notify(); + } + + public synchronized void release() throws InterruptedException{ + while(this.signals == 0) wait(); + this.signals--; + this.notify(); + } +} +Notice how the take() method now blocks if the number of signals is equal to the upper bound. Not until a thread has called release() will the thread calling take() be allowed to deliver its signal, if the BoundedSemaphore has reached its upper signal limit. + +Using Semaphores as Locks + +It is possible to use a bounded semaphore as a lock. To do so, set the upper bound to 1, and have the call to take() and release() guard the critical section. Here is an example: + +BoundedSemaphore semaphore = new BoundedSemaphore(1); + +... + +semaphore.take(); + +try{ + //critical section +} finally { + semaphore.release(); +} +In contrast to the signaling use case the methods take() and release() are now called by the same thread. Since only one thread is allowed to take the semaphore, all other threads calling take() will be blocked until release() is called. The call to release() will never block since there has always been a call to take() first. + +You can also use a bounded semaphore to limit the number of threads allowed into a section of code. For instance, in the example above, what would happen if you set the limit of the BoundedSemaphore to 5? 5 threads would be allowed to enter the critical section at a time. You would have to make sure though, that the thread operations do not conflict for these 5 threads, or you application will fail. + +The relase() method is called from inside a finally-block to make sure it is called even if an exception is thrown from the critical section. + From 098313be2895188e9a4622036262fe0e2d7e1a0d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:51:59 +0800 Subject: [PATCH 241/524] Published with https://stackedit.io/ --- ...73\345\241\236\351\230\237\345\210\227.md" | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 "Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" diff --git "a/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" "b/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" new file mode 100644 index 0000000..96bd0dc --- /dev/null +++ "b/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" @@ -0,0 +1,54 @@ +#20.阻塞队列 + +A blocking queue is a queue that blocks when you try to dequeue from it and the queue is empty, or if you try to enqueue items to it and the queue is already full. A thread trying to dequeue from an empty queue is blocked until some other thread inserts an item into the queue. A thread trying to enqueue an item in a full queue is blocked until some other thread makes space in the queue, either by dequeuing one or more items or clearing the queue completely. + +Here is a diagram showing two threads cooperating via a blocking queue: + + + +A BlockingQueue with one thread putting into it, and another thread taking from it. +A BlockingQueue with one thread putting into it, and another thread taking from it. +Java 5 comes with blocking queue implementations in the java.util.concurrent package. You can read about that class in my java.util.concurrent.BlockingQueue tutorial. Even if Java 5 comes with a blocking queue implementation, it can be useful to know the theory behind their implementation. + + +Blocking Queue Implementation + +The implementation of a blocking queue looks similar to a Bounded Semaphore. Here is a simple implementation of a blocking queue: + +public class BlockingQueue { + + private List queue = new LinkedList(); + private int limit = 10; + + public BlockingQueue(int limit){ + this.limit = limit; + } + + + public synchronized void enqueue(Object item) + throws InterruptedException { + while(this.queue.size() == this.limit) { + wait(); + } + if(this.queue.size() == 0) { + notifyAll(); + } + this.queue.add(item); + } + + + public synchronized Object dequeue() + throws InterruptedException{ + while(this.queue.size() == 0){ + wait(); + } + if(this.queue.size() == this.limit){ + notifyAll(); + } + + return this.queue.remove(0); + } + +} + +Notice how notifyAll() is only called from enqueue() and dequeue() if the queue size is equal to the size bounds (0 or limit). If the queue size is not equal to either bound when enqueue() or dequeue() is called, there can be no threads waiting to either enqueue or dequeue items. \ No newline at end of file From e548ac742774ef62ddfbe86d8300167476c2360d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:53:43 +0800 Subject: [PATCH 242/524] Published with https://stackedit.io/ --- ...1.\347\272\277\347\250\213\346\261\240.md" | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 "Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" diff --git "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" new file mode 100644 index 0000000..c457eef --- /dev/null +++ "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" @@ -0,0 +1,83 @@ +#21.线程池 + +Thread Pools are useful when you need to limit the number of threads running in your application at the same time. There is a performance overhead associated with starting a new thread, and each thread is also allocated some memory for its stack etc. + +Instead of starting a new thread for every task to execute concurrently, the task can be passed to a thread pool. As soon as the pool has any idle threads the task is assigned to one of them and executed. Internally the tasks are inserted into a Blocking Queue which the threads in the pool are dequeuing from. When a new task is inserted into the queue one of the idle threads will dequeue it successfully and execute it. The rest of the idle threads in the pool will be blocked waiting to dequeue tasks. + +Thread pools are often used in multi threaded servers. Each connection arriving at the server via the network is wrapped as a task and passed on to a thread pool. The threads in the thread pool will process the requests on the connections concurrently. A later trail will get into detail about implementing multithreaded servers in Java. + +Java 5 comes with built in thread pools in the java.util.concurrent package, so you don't have to implement your own thread pool. You can read more about it in my text on the java.util.concurrent.ExecutorService. Still it can be useful to know a bit about the implementation of a thread pool anyways. + +Here is a simple thread pool implementation: + +public class ThreadPool { + + private BlockingQueue taskQueue = null; + private List threads = new ArrayList (); + private boolean isStopped = false; + + public ThreadPool(int noOfThreads, int maxNoOfTasks){ + taskQueue = new BlockingQueue(maxNoOfTasks); + + for(int i=0; i Date: Tue, 16 Sep 2014 01:55:58 +0800 Subject: [PATCH 243/524] Published with https://stackedit.io/ --- ...20\345\220\214\346\255\245\345\231\250.md" | 270 ++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 "Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" new file mode 100644 index 0000000..89aa638 --- /dev/null +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -0,0 +1,270 @@ + +#22.剖析同步器 + +Even if many synchronizers (locks, semaphores, blocking queue etc.) are different in function, they are often not that different in their internal design. In other words, they consist of the same (or similar) basic parts internally. Knowing these basic parts can be a great help when designing synchronizers. It is these parts this text looks closer at. + +Note: The content of this text is a part result of a M.Sc. student project at the IT University of Copenhagen in the spring 2004 by Jakob Jenkov, Toke Johansen and Lars Bjørn. During this project we asked Doug Lea if he knew of similar work. Interestingly he had come up with similar conclusions independently of this project during the development of the Java 5 concurrency utilities. Doug Lea's work, I believe, is described in the book "Java Concurrency in Practice". This book also contains a chapter with the title "Anatomy of a Synchronizer" with content similar to this text, though not exactly the same. + +The purpose of most (if not all) synchronizers is to guard some area of the code (critical section) from concurrent access by threads. To do this the following parts are often needed in a synchronizer: + +State +Access Condition +State Changes +Notification Strategy +Test and Set Method +Set Method +Not all synchronizers have all of these parts, and those that have may not have them exactly as they are described here. Usually you can find one or more of these parts, though. + +State + +The state of a synchronizer is used by the access condition to determine if a thread can be granted access. In a Lock the state is kept in a boolean saying whether the Lock is locked or not. In a Bounded Semaphore the internal state is kept in a counter (int) and an upper bound (int) which state the current number of "takes" and the maximum number of "takes". In a Blocking Queue the state is kept in the List of elements in the queue and the maximum queue size (int) member (if any). + +Here are two code snippets from both Lock and a BoundedSemaphore. The state code is marked in bold. + +public class Lock{ + + //state is kept here + private boolean isLocked = false; + + public synchronized void lock() + throws InterruptedException{ + while(isLocked){ + wait(); + } + isLocked = true; + } + + ... +} +public class BoundedSemaphore { + + //state is kept here + private int signals = 0; + private int bound = 0; + + public BoundedSemaphore(int upperBound){ + this.bound = upperBound; + } + + public synchronized void take() throws InterruptedException{ + while(this.signals == bound) wait(); + this.signal++; + this.notify(); + } + ... +} +Access Condition + +The access conditions is what determines if a thread calling a test-and-set-state method can be allowed to set the state or not. The access condition is typically based on the state of the synchronizer. The access condition is typically checked in a while loop to guard against Spurious Wakeups. When the access condition is evaluated it is either true or false. + +In a Lock the access condition simply checks the value of the isLocked member variable. In a Bounded Semaphore there are actually two access conditions depending on whether you are trying to "take" or "release" the semaphore. If a thread tries to take the semaphore the signals variable is checked against the upper bound. If a thread tries to release the semaphore the signals variable is checked against 0. + +Here are two code snippets of a Lock and a BoundedSemaphore with the access condition marked in bold. Notice how the conditions is always checked inside a while loop. + +public class Lock{ + + private boolean isLocked = false; + + public synchronized void lock() + throws InterruptedException{ + //access condition + while(isLocked){ + wait(); + } + isLocked = true; + } + + ... +} +public class BoundedSemaphore { + private int signals = 0; + private int bound = 0; + + public BoundedSemaphore(int upperBound){ + this.bound = upperBound; + } + + public synchronized void take() throws InterruptedException{ + //access condition + while(this.signals == bound) wait(); + this.signals++; + this.notify(); + } + + public synchronized void release() throws InterruptedException{ + //access condition + while(this.signals == 0) wait(); + this.signals--; + this.notify(); + } +} +State Changes + +Once a thread gains access to the critical section it has to change the state of the synchronizer to (possibly) block other threads from entering it. In other words, the state needs to reflect the fact that a thread is now executing inside the critical section. This should affect the access conditions of other threads attempting to gain access. + +In a Lock the state change is the code setting isLocked = true. In a semaphore it is either the code signals-- or signals++; + +Here are two code snippets with the state change code marked in bold: + +public class Lock{ + + private boolean isLocked = false; + + public synchronized void lock() + throws InterruptedException{ + while(isLocked){ + wait(); + } + //state change + isLocked = true; + } + + public synchronized void unlock(){ + //state change + isLocked = false; + notify(); + } +} +public class BoundedSemaphore { + private int signals = 0; + private int bound = 0; + + public BoundedSemaphore(int upperBound){ + this.bound = upperBound; + } + + public synchronized void take() throws InterruptedException{ + while(this.signals == bound) wait(); + //state change + this.signals++; + this.notify(); + } + + public synchronized void release() throws InterruptedException{ + while(this.signals == 0) wait(); + //state change + this.signals--; + this.notify(); + } +} +Notification Strategy + +Once a thread has changed the state of a synchronizer it may sometimes need to notify other waiting threads about the state change. Perhaps this state change might turn the access condition true for other threads. + +Notification Strategies typically fall into three categories. + +Notify all waiting threads. +Notify 1 random of N waiting threads. +Notify 1 specific of N waiting thread. +Notifying all waiting threads is pretty easy. All waiting threads call wait() on the same object. Once a thread want to notify the waiting threads it calls notifyAll() on the object the waiting threads called wait() on. + +Notifying a single random waiting thread is also pretty easy. Just have the notifying thread call notify() on the object the waiting threads have called wait() on. Calling notify makes no guarantee about which of the waiting threads will be notified. Hence the term "random waiting thread". + +Sometimes you may need to notify a specific rather than a random waiting thread. For instance if you need to guarantee that waiting threads are notified in a specific order, be it the order they called the synchronizer in, or some prioritized order. To achive this each waiting thread must call wait() on its own, separate object. When the notifying thread wants to notify a specific waiting thread it will call notify() on the object this specific thread has called wait() on. An example of this can be found in the text Starvation and Fairness. + +Below is a code snippet with the notification strategy (notify 1 random waiting thread) marked in bold: + +public class Lock{ + + private boolean isLocked = false; + + public synchronized void lock() + throws InterruptedException{ + while(isLocked){ + //wait strategy - related to notification strategy + wait(); + } + isLocked = true; + } + + public synchronized void unlock(){ + isLocked = false; + notify(); //notification strategy + } +} +Test and Set Method + +Synchronizer most often have two types of methods of which test-and-set is the first type (set is the other). Test-and-set means that the thread calling this method tests the internal state of the synchronizer against the access condition. If the condition is met the thread sets the internal state of the synchronizer to reflect that the thread has gained access. + +The state transition usually results in the access condition turning false for other threads trying to gain access, but may not always do so. For instance, in a Read - Write Lock a thread gaining read access will update the state of the read-write lock to reflect this, but other threads requesting read access will also be granted access as long as no threads has requested write access. + +It is imperative that the test-and-set operations are executed atomically meaning no other threads are allowed to execute in the test-and-set method in between the test and the setting of the state. + +The program flow of a test-and-set method is usually something along the lines of: + +Set state before test if necessary +Test state against access condition +If access condition is not met, wait +If access condition is met, set state, and notify waiting threads if necessary +The lockWrite() method of a ReadWriteLock class shown below is an example of a test-and-set method. Threads calling lockWrite() first sets the state before the test (writeRequests++). Then it tests the internal state against the access condition in the canGrantWriteAccess() method. If the test succeeds the internal state is set again before the method is exited. Notice that this method does not notify waiting threads. + +public class ReadWriteLock{ + private Map readingThreads = + new HashMap (); + + private int writeAccesses = 0; + private int writeRequests = 0; + private Thread writingThread = null; + + ... + + + public synchronized void lockWrite() throws InterruptedException{ + writeRequests++; + Thread callingThread = Thread.currentThread(); + while(! canGrantWriteAccess(callingThread)){ + wait(); + } + writeRequests--; + writeAccesses++; + writingThread = callingThread; + } + + + ... +} +The BoundedSemaphore class shown below has two test-and-set methods: take() and +release(). Both methods test and sets the internal state. + +public class BoundedSemaphore { + private int signals = 0; + private int bound = 0; + + public BoundedSemaphore(int upperBound){ + this.bound = upperBound; + } + + + public synchronized void take() throws InterruptedException{ + while(this.signals == bound) wait(); + this.signals++; + this.notify(); + } + + public synchronized void release() throws InterruptedException{ + while(this.signals == 0) wait(); + this.signals--; + this.notify(); + } + +} +Set Method + +The set method is the second type of method that synchronizers often contain. The set method just sets the internal state of the synchronizer without testing it first. A typical example of a set method is the unlock() method of a Lock class. A thread holding the lock can always unlock it without having to test if the Lock is unlocked. + +The program flow of a set method is usually along the lines of: + +Set internal state +Notify waiting threads +Here is an example unlock() method: + +public class Lock{ + + private boolean isLocked = false; + + public synchronized void unlock(){ + isLocked = false; + notify(); + } + +} \ No newline at end of file From 1937d25a3b96bb9a64a8018261c48eb2ec7c5cbf Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:58:58 +0800 Subject: [PATCH 244/524] =?UTF-8?q?Update=2010.=E7=BA=BF=E7=A8=8B=E9=80=9A?= =?UTF-8?q?=E4=BF=A1.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../10.\347\272\277\347\250\213\351\200\232\344\277\241.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/10.\347\272\277\347\250\213\351\200\232\344\277\241.md" "b/Java-Concurrency/10.\347\272\277\347\250\213\351\200\232\344\277\241.md" index 126f4a0..5d4878d 100644 --- "a/Java-Concurrency/10.\347\272\277\347\250\213\351\200\232\344\277\241.md" +++ "b/Java-Concurrency/10.\347\272\277\347\250\213\351\200\232\344\277\241.md" @@ -1,4 +1,4 @@ -#09.线程通信 +#10.线程通信 线程通信的目的在于:让线程之间可以彼此发送信号。因此,线程通信也让线程等待其他线程发送的信号。举个例子,线程B等待线程A的信号,这个信号用于通知线程B数据已经准备就绪。 @@ -205,4 +205,4 @@ If the doNotify() method had called notifyAll() instead of notify(), all waiting You may be tempted then to always call notifyAll() instead notify(), but this is a bad idea performance wise. There is no reason to wake up all threads waiting when only one of them can respond to the signal. -So: Don't use global objects, string constants etc. for wait() / notify() mechanisms. Use an object that is unique to the construct using it. For instance, each MyWaitNotify3 (example from earlier sections) instance has its own MonitorObject instance rather than using the empty string for wait() / notify() calls. \ No newline at end of file +So: Don't use global objects, string constants etc. for wait() / notify() mechanisms. Use an object that is unique to the construct using it. For instance, each MyWaitNotify3 (example from earlier sections) instance has its own MonitorObject instance rather than using the empty string for wait() / notify() calls. From 02204812572352666f1fd6745ce67c27b8da443c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:59:16 +0800 Subject: [PATCH 245/524] =?UTF-8?q?Update=2011.=E6=AD=BB=E9=94=81.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "Java-Concurrency/11.\346\255\273\351\224\201.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/11.\346\255\273\351\224\201.md" "b/Java-Concurrency/11.\346\255\273\351\224\201.md" index be1ac0a..6d5e624 100644 --- "a/Java-Concurrency/11.\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/11.\346\255\273\351\224\201.md" @@ -1,4 +1,4 @@ -#10.死锁 +#11.死锁 死锁是指两个或多个线程等待其他处于死锁状态的线程所持有的锁。死锁通常发生在多个线程同时但以不同的顺序请求同一组锁的时候。 @@ -93,4 +93,4 @@ Transaction 1, request 2, tries to lock record 2 for update. Transaction 2, request 2, tries to lock record 1 for update. ``` -因为锁发生在不同的请求中,并且对于一个事务来说不可能提前知道所有它需要的锁,因此很难检测和避免数据库事务中的死锁。 \ No newline at end of file +因为锁发生在不同的请求中,并且对于一个事务来说不可能提前知道所有它需要的锁,因此很难检测和避免数据库事务中的死锁。 From d388ddd111574cf6bd96ff8331e88f334818de47 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 01:59:31 +0800 Subject: [PATCH 246/524] =?UTF-8?q?Update=2012.=E9=A2=84=E9=98=B2=E6=AD=BB?= =?UTF-8?q?=E9=94=81.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../12.\351\242\204\351\230\262\346\255\273\351\224\201.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/12.\351\242\204\351\230\262\346\255\273\351\224\201.md" "b/Java-Concurrency/12.\351\242\204\351\230\262\346\255\273\351\224\201.md" index 3f6bcf2..0c6b61d 100644 --- "a/Java-Concurrency/12.\351\242\204\351\230\262\346\255\273\351\224\201.md" +++ "b/Java-Concurrency/12.\351\242\204\351\230\262\346\255\273\351\224\201.md" @@ -1,4 +1,4 @@ -#11.预防死锁 +#12.预防死锁 在某些情况,死锁是可以预防的。下面介绍三种可以预防死锁的技术: @@ -88,4 +88,4 @@ So what do the threads do if a deadlock is detected? One possible action is to release all locks, backup, wait a random amount of time and then retry. This is similar to the simpler lock timeout mechanism except threads only backup when a deadlock has actually occurred. Not just because their lock requests timed out. However, if a lot of threads are competing for the same locks they may repeatedly end up in a deadlock even if they back up and wait. -A better option is to determine or assign a priority of the threads so that only one (or a few) thread backs up. The rest of the threads continue taking the locks they need as if no deadlock had occurred. If the priority assigned to the threads is fixed, the same threads will always be given higher priority. To avoid this you may assign the priority randomly whenever a deadlock is detected. \ No newline at end of file +A better option is to determine or assign a priority of the threads so that only one (or a few) thread backs up. The rest of the threads continue taking the locks they need as if no deadlock had occurred. If the priority assigned to the threads is fixed, the same threads will always be given higher priority. To avoid this you may assign the priority randomly whenever a deadlock is detected. From 4d1a995965a013e472c6fe79db3a24a396268523 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:00:01 +0800 Subject: [PATCH 247/524] =?UTF-8?q?Update=2014.=E5=B5=8C=E5=A5=97=E7=AE=A1?= =?UTF-8?q?=E7=A8=8B=E9=94=81=E6=AD=BB.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...45\227\347\256\241\347\250\213\351\224\201\346\255\273.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/14.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" "b/Java-Concurrency/14.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" index 63f1351..8752fdd 100644 --- "a/Java-Concurrency/14.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" +++ "b/Java-Concurrency/14.\345\265\214\345\245\227\347\256\241\347\250\213\351\224\201\346\255\273.md" @@ -1,4 +1,4 @@ -#13.嵌套管程锁死(Nested Monitor Lockout) +#14.嵌套管程锁死(Nested Monitor Lockout) ##嵌套管程锁死如何发生 @@ -130,4 +130,4 @@ The two situations are not equal though. As explained in the text on Deadlock a 两者的不同点如下: * 在死锁中,两个线程互相等待对方释放锁。 -* 在嵌套管程锁死中,线程1持有锁A,并等待线程2的信号,而线程2需要锁A才能够发送信号给线程1. \ No newline at end of file +* 在嵌套管程锁死中,线程1持有锁A,并等待线程2的信号,而线程2需要锁A才能够发送信号给线程1. From 6751324c906b9d113005b250ae125b797e7d0fa8 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:00:22 +0800 Subject: [PATCH 248/524] Update 15.Slipped Conditions.md --- Java-Concurrency/15.Slipped Conditions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Java-Concurrency/15.Slipped Conditions.md b/Java-Concurrency/15.Slipped Conditions.md index 4af0ffb..1e9e919 100644 --- a/Java-Concurrency/15.Slipped Conditions.md +++ b/Java-Concurrency/15.Slipped Conditions.md @@ -1,4 +1,4 @@ -#14.Slipped Conditions +#15.Slipped Conditions What is Slipped Conditions? @@ -226,4 +226,4 @@ The return; statement in the synchronized(this) block is not necessary. It is ju The observant reader will notice that the above implementation of a fair lock still suffers from a missed signal problem. Imagine that the FairLock instance is locked when a thread calls lock(). After the first synchronized(this) block mustWait is true. Then imagine that the thread calling lock() is preempted, and the thread that locked the lock calls unlock(). If you look at the unlock() implementation shown earlier, you will notice that it calls queueObject.notify(). But, since the thread waiting in lock() has not yet called queueObject.wait(), the call to queueObject.notify() passes into oblivion. The signal is missed. When the thread calling lock() right after calls queueObject.wait() it will remain blocked until some other thread calls unlock(), which may never happen. -The missed signals problems is the reason that the FairLock implementation shown in the text Starvation and Fairness has turned the QueueObject class into a semaphore with two methods: doWait() and doNotify(). These methods store and react the signal internally in the QueueObject. That way the signal is not missed, even if doNotify() is called before doWait(). \ No newline at end of file +The missed signals problems is the reason that the FairLock implementation shown in the text Starvation and Fairness has turned the QueueObject class into a semaphore with two methods: doWait() and doNotify(). These methods store and react the signal internally in the QueueObject. That way the signal is not missed, even if doNotify() is called before doWait(). From e97b181b0b29e7723f2565be21f8e8c3df2e9905 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:00:37 +0800 Subject: [PATCH 249/524] =?UTF-8?q?Update=2016.Java=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E9=94=81.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../16.Java\344\270\255\347\232\204\351\224\201.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/16.Java\344\270\255\347\232\204\351\224\201.md" "b/Java-Concurrency/16.Java\344\270\255\347\232\204\351\224\201.md" index 67667bb..da983ec 100644 --- "a/Java-Concurrency/16.Java\344\270\255\347\232\204\351\224\201.md" +++ "b/Java-Concurrency/16.Java\344\270\255\347\232\204\351\224\201.md" @@ -1,4 +1,4 @@ -#15.Java中的锁 +#16.Java中的锁 **锁**跟**synchronized**的一样,是Java中的一种同步机制,但要比synchronized复杂得多。在Java 5之前,锁(以及其它更高级的线程同步机制)是由synchronized同步块的方式实现的,我们还不能完全摆脱synchronized关键字。 @@ -182,4 +182,4 @@ try{ } ``` -这个小小的结构改变可以保证当临界区的代码抛出异常时`unlock()`总可以被调用。当临界区代码抛出异常时,如果finally块中的`unlock()`方法没有被调用,那么Lock实例将永远被锁住,调用`lock()`方法的线程将陷入无止境的阻塞状态。 \ No newline at end of file +这个小小的结构改变可以保证当临界区的代码抛出异常时`unlock()`总可以被调用。当临界区代码抛出异常时,如果finally块中的`unlock()`方法没有被调用,那么Lock实例将永远被锁住,调用`lock()`方法的线程将陷入无止境的阻塞状态。 From e8edd60279ddbd551f1055aaaa95f7f42efa1a43 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:00:54 +0800 Subject: [PATCH 250/524] =?UTF-8?q?Update=2017.Java=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E8=AF=BB=E5=86=99=E9=94=81.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...70\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 1847413..4af75f3 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -1,4 +1,4 @@ -#16.Java中的读/写锁 +#17.Java中的读/写锁 A read / write lock is more sophisticated lock than the Lock implementations shown in the text Locks in Java. Imagine you have an application that reads and writes some resource, but writing it is not done as much as reading it is. Two threads reading the same resource does not cause problems for each other, so multiple threads that want to read the resource are granted access at the same time, overlapping. But, if a single thread wants to write to the resource, no other reads nor writes must be in progress at the same time. To solve this problem of allowing multiple readers but only one writer, you will need a read / write lock. @@ -370,4 +370,4 @@ try{ } finally { lock.unlockWrite(); } -This little construct makes sure that the ReadWriteLock is unlocked in case an exception is thrown from the code in the critical section. If unlockWrite() was not called from inside a finally-clause, and an exception was thrown from the critical section, the ReadWriteLock would remain write locked forever, causing all threads calling lockRead() or lockWrite() on that ReadWriteLock instance to halt indefinately. The only thing that could unlock the ReadWriteLockagain would be if the ReadWriteLock is reentrant, and the thread that had it locked when the exception was thrown, later succeeds in locking it, executing the critical section and calling unlockWrite() again afterwards. That would unlock the ReadWriteLock again. But why wait for that to happen, if it happens? Calling unlockWrite() from a finally-clause is a much more robust solution. \ No newline at end of file +This little construct makes sure that the ReadWriteLock is unlocked in case an exception is thrown from the code in the critical section. If unlockWrite() was not called from inside a finally-clause, and an exception was thrown from the critical section, the ReadWriteLock would remain write locked forever, causing all threads calling lockRead() or lockWrite() on that ReadWriteLock instance to halt indefinately. The only thing that could unlock the ReadWriteLockagain would be if the ReadWriteLock is reentrant, and the thread that had it locked when the exception was thrown, later succeeds in locking it, executing the critical section and calling unlockWrite() again afterwards. That would unlock the ReadWriteLock again. But why wait for that to happen, if it happens? Calling unlockWrite() from a finally-clause is a much more robust solution. From 66db28cc2cf1302c7f13040511be7ed4f0c514fb Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:01:14 +0800 Subject: [PATCH 251/524] =?UTF-8?q?Update=2018.=E9=87=8D=E5=85=A5=E9=94=81?= =?UTF-8?q?=E6=AD=BB.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../18.\351\207\215\345\205\245\351\224\201\346\255\273.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/18.\351\207\215\345\205\245\351\224\201\346\255\273.md" "b/Java-Concurrency/18.\351\207\215\345\205\245\351\224\201\346\255\273.md" index ff5a4c3..e438f20 100644 --- "a/Java-Concurrency/18.\351\207\215\345\205\245\351\224\201\346\255\273.md" +++ "b/Java-Concurrency/18.\351\207\215\345\205\245\351\224\201\346\255\273.md" @@ -1,4 +1,4 @@ -#17.重入锁死 +#18.重入锁死 Reentrance lockout is a situation similar to deadlock and nested monitor lockout. Reentrance lockout is also covered in part in the texts on Locks and Read / Write Locks. @@ -41,4 +41,4 @@ To avoid reentrance lockouts you have two options: Avoid writing code that reenters locks Use reentrant locks -Which of these options suit your project best depends on your concrete situation. Reentrant locks often don't perform as well as non-reentrant locks, and they are harder to implement, but this may not necessary be a problem in your case. Whether or not your code is easier to implement with or without lock reentrance must be determined case by case. \ No newline at end of file +Which of these options suit your project best depends on your concrete situation. Reentrant locks often don't perform as well as non-reentrant locks, and they are harder to implement, but this may not necessary be a problem in your case. Whether or not your code is easier to implement with or without lock reentrance must be determined case by case. From e51b94c979f3c6b3dc617c26f21a947bc4a94a33 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:01:33 +0800 Subject: [PATCH 252/524] =?UTF-8?q?Update=2019.=E4=BF=A1=E5=8F=B7=E9=87=8F?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index 3605de7..706ac5a 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -1,4 +1,4 @@ -19.信号量 +#19.信号量 A Semaphore is a thread synchronization construct that can be used either to send signals between threads to avoid missed signals, or to guard a critical section like you would with a lock. Java 5 comes with semaphore implementations in the java.util.concurrent package so you don't have to implement your own semaphores. Still, it can be useful to know the theory behind their implementation and use. From ecfffaedf14b378086e1a0e48ec475f00d9a3e31 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:02:10 +0800 Subject: [PATCH 253/524] =?UTF-8?q?Update=2013.=E9=A5=A5=E9=A5=BF=E5=92=8C?= =?UTF-8?q?=E5=85=AC=E5=B9=B3.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...45\245\351\245\277\345\222\214\345\205\254\345\271\263.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/13.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" "b/Java-Concurrency/13.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" index 7074380..62c3b95 100644 --- "a/Java-Concurrency/13.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" +++ "b/Java-Concurrency/13.\351\245\245\351\245\277\345\222\214\345\205\254\345\271\263.md" @@ -1,4 +1,4 @@ -#12.饥饿和公平(Starvation and Fairness) +#13.饥饿和公平(Starvation and Fairness) 如果一个线程由于CPU时间全部被其他线程抢占而得不到CPU时间,这就称为**饥饿(Starvation)**。这个线程因为得不到CPU机会而“饿死(starved to death)"。解决饥饿的方案称为**公平(Fairness)**--所有的线程都能公平地获得CPU时间。 @@ -190,4 +190,4 @@ Finally, notice how the queueObject.doWait() is called inside a try - catch bloc ##性能(A Note on Performance) -If you compare the Lock and FairLock classes you will notice that there is somewhat more going on inside the lock() and unlock() in the FairLock class. This extra code will cause the FairLock to be a sligtly slower synchronization mechanism than Lock. How much impact this will have on your application depends on how long time the code in the critical section guarded by the FairLock takes to execute. The longer this takes to execute, the less significant the added overhead of the synchronizer is. It does of course also depend on how often this code is called. \ No newline at end of file +If you compare the Lock and FairLock classes you will notice that there is somewhat more going on inside the lock() and unlock() in the FairLock class. This extra code will cause the FairLock to be a sligtly slower synchronization mechanism than Lock. How much impact this will have on your application depends on how long time the code in the critical section guarded by the FairLock takes to execute. The longer this takes to execute, the less significant the added overhead of the synchronizer is. It does of course also depend on how often this code is called. From aa9c2dacb92cb7f0adb04c4d414506d26f63b704 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:03:38 +0800 Subject: [PATCH 254/524] Published with https://stackedit.io/ From 8111bb6bfeeec87cd0e938d9fa2fcb660c336f29 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:08:10 +0800 Subject: [PATCH 255/524] Published with https://stackedit.io/ --- ...70\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 4af75f3..6383f3e 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -4,7 +4,7 @@ A read / write lock is more sophisticated lock than the Lock implementations sho Java 5 comes with read / write lock implementations in the java.util.concurrent package. Even so, it may still be useful to know the theory behind their implementation. -##Read / Write Lock Java Implementation +##Java中读/写锁的实现(Read / Write Lock Java Implementation) First let's summarize the conditions for getting read and write access to the resource: @@ -61,7 +61,7 @@ Inside the ReadWriteLock there are threads waiting for read access, and threads Calling notifyAll() also has another advantage. If multiple threads are waiting for read access and none for write access, and unlockWrite() is called, all threads waiting for read access are granted read access at once - not one by one. -##Read / Write Lock Reentrance +##读/写锁的可重入性(Read / Write Lock Reentrance) The ReadWriteLock class shown earlier is not reentrant. If a thread that has write access requests it again, it will block because there is already one writer - itself. Furthermore, consider this case: From f52eb3386181407b0c0f71da28241b0f07bec8ca Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:22:29 +0800 Subject: [PATCH 256/524] Published with https://stackedit.io/ --- ...70\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 4 ++++ 1 file changed, 4 insertions(+) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 6383f3e..a8edcfa 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -1,7 +1,11 @@ #17.Java中的读/写锁 +Java中,读/写锁的实现比普通锁的实现更加复杂。想象一个读写资源的应用程序,读操作比写操作要频繁得多。假如两个线程同时对同一个资源进行读操作,则不会发生任何问题,因此,如果多个线程同时请求对资源进行读操作将可同时被授权并对资源进行读取。 + A read / write lock is more sophisticated lock than the Lock implementations shown in the text Locks in Java. Imagine you have an application that reads and writes some resource, but writing it is not done as much as reading it is. Two threads reading the same resource does not cause problems for each other, so multiple threads that want to read the resource are granted access at the same time, overlapping. But, if a single thread wants to write to the resource, no other reads nor writes must be in progress at the same time. To solve this problem of allowing multiple readers but only one writer, you will need a read / write lock. +读/写锁是比文字锁在Java中所示的Lock实现更复杂的锁。想象一下,你有读取和写入一些资源的应用程序,但是写不这样做尽可能多读书是。两个线程读取相同的资源不会造成问题,对于想要阅读的资源交相辉映,让多个线程被授予在同一时间访问,重叠。但是,如果一个线程想要写的资源,没有其他读也不写操作必须是在进步的同时。为了解决允许多个读者的这个问题,但只有一个作家,你将需要一个读/写锁。 + Java 5 comes with read / write lock implementations in the java.util.concurrent package. Even so, it may still be useful to know the theory behind their implementation. ##Java中读/写锁的实现(Read / Write Lock Java Implementation) From f23bbe8593a07ac6faa1abf8a35187c8a818d00f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:31:48 +0800 Subject: [PATCH 257/524] Published with https://stackedit.io/ --- ...55\347\232\204\350\257\273\345\206\231\351\224\201.md" | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index a8edcfa..7211542 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -1,12 +1,8 @@ #17.Java中的读/写锁 -Java中,读/写锁的实现比普通锁的实现更加复杂。想象一个读写资源的应用程序,读操作比写操作要频繁得多。假如两个线程同时对同一个资源进行读操作,则不会发生任何问题,因此,如果多个线程同时请求对资源进行读操作将可同时被授权并对资源进行读取。 +Java中,读/写锁的实现比普通锁的实现更加复杂。想象一个读写资源的应用程序,读操作比写操作要频繁得多。假如两个线程同时对同一个资源进行读操作,则不会发生任何问题,因此,如果多个线程同时请求对资源进行读操作将可同时被授权并对资源进行读取。但是,如果有一个线程对资源进行写操作,则不应该存在其他写线程或读线程在执行。我们可以使用读/写锁来实现这种需求。 -A read / write lock is more sophisticated lock than the Lock implementations shown in the text Locks in Java. Imagine you have an application that reads and writes some resource, but writing it is not done as much as reading it is. Two threads reading the same resource does not cause problems for each other, so multiple threads that want to read the resource are granted access at the same time, overlapping. But, if a single thread wants to write to the resource, no other reads nor writes must be in progress at the same time. To solve this problem of allowing multiple readers but only one writer, you will need a read / write lock. - -读/写锁是比文字锁在Java中所示的Lock实现更复杂的锁。想象一下,你有读取和写入一些资源的应用程序,但是写不这样做尽可能多读书是。两个线程读取相同的资源不会造成问题,对于想要阅读的资源交相辉映,让多个线程被授予在同一时间访问,重叠。但是,如果一个线程想要写的资源,没有其他读也不写操作必须是在进步的同时。为了解决允许多个读者的这个问题,但只有一个作家,你将需要一个读/写锁。 - -Java 5 comes with read / write lock implementations in the java.util.concurrent package. Even so, it may still be useful to know the theory behind their implementation. +Java 5的`java.util.concurrent`包含了读写锁。即使如此,了解读写锁的实现原理也是非常有用的。 ##Java中读/写锁的实现(Read / Write Lock Java Implementation) From 98d10675673cb77452977004c338bf7708ce6a7f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 02:38:22 +0800 Subject: [PATCH 258/524] Published with https://stackedit.io/ --- ...0\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 7211542..5c56693 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -6,10 +6,13 @@ Java 5的`java.util.concurrent`包含了读写锁。即使如此,了解读写 ##Java中读/写锁的实现(Read / Write Lock Java Implementation) -First let's summarize the conditions for getting read and write access to the resource: +首先,我们对写操作和读操作做一个概述: +``` Read Access If no threads are writing, and no threads have requested write access. Write Access If no threads are reading or writing. +``` + If a thread wants to read the resource, it is okay as long as no threads are writing to it, and no threads have requested write access to the resource. By up-prioritizing write-access requests we assume that write requests are more important than read-requests. Besides, if reads are what happens most often, and we did not up-prioritize writes, starvation could occur. Threads requesting write access would be blocked until all readers had unlocked the ReadWriteLock. If new threads were constantly granted read access the thread waiting for write access would remain blocked indefinately, resulting in starvation. Therefore a thread can only be granted read access if no thread has currently locked the ReadWriteLock for writing, or requested it locked for writing. A thread that wants write access to the resource can be granted so when no threads are reading nor writing to the resource. It doesn't matter how many threads have requested write access or in what sequence, unless you want to guarantee fairness between threads requesting write access. From f52ff938c10fa150b400b9f3c1ac9e56439ba31f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 09:09:43 +0800 Subject: [PATCH 259/524] =?UTF-8?q?Rename=2009.Java=E4=B8=AD=E7=9A=84volat?= =?UTF-8?q?ile=E5=85=B3=E9=94=AE=E5=AD=97.md=20to=2009.Java=E7=9A=84volati?= =?UTF-8?q?le=E5=85=B3=E9=94=AE=E5=AD=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...va\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "Java-Concurrency/09.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" => "Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" (100%) diff --git "a/Java-Concurrency/09.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" similarity index 100% rename from "Java-Concurrency/09.Java\344\270\255\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" rename to "Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" From 521d0a3f7625a1ca8fab3e43dfc1f6f15190ea71 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 09:30:20 +0800 Subject: [PATCH 260/524] Published with https://stackedit.io/ --- ...le\345\205\263\351\224\256\345\255\227.md" | 142 +++++------------- 1 file changed, 38 insertions(+), 104 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 67de7c1..588c4a0 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -1,136 +1,70 @@ -#19.信号量 +#09.Java的volatile关键字 -A Semaphore is a thread synchronization construct that can be used either to send signals between threads to avoid missed signals, or to guard a critical section like you would with a lock. Java 5 comes with semaphore implementations in the java.util.concurrent package so you don't have to implement your own semaphores. Still, it can be useful to know the theory behind their implementation and use. +The Java volatile keyword is used to mark a Java variable as "being stored in main memory". More precisely that means, that every read of a volatile variable will be read from the computer's main memory, and not from the CPU cache, and that every write to a volatile variable will be written to main memory, and not just to the CPU cache. -Java 5 comes with a built-in Semaphore so you don't have to implement your own. You can read more about it in the java.util.concurrent.Semaphore text, in my java.util.concurrent tutorial. +Actually, since Java 5 the volatile keyword guarantees more than just that volatile variables are written to and read from main memory. I will explain that in the following sections. -Simple Semaphore +##Java volatile Guarantees Variable Visibility -Here is a simple Semaphore implementation: +The Java volatile keyword guarantees visibility of changes to variables across threads. This may sound a bit abstract, so let me elaborate. -public class Semaphore { - private boolean signal = false; +In a multithreaded application where the threads operate on non-volatile variables, each thread may copy variables from main memory into a CPU cache while working on them, for performance reasons. If your computer contains more than one CPU, each thread may run on a different CPU. That means, that each thread may copy the variables into the CPU cache of different CPUs. This diagram illustrates such a situation: - public synchronized void take() { - this.signal = true; - this.notify(); - } + - public synchronized void release() throws InterruptedException{ - while(!this.signal) wait(); - this.signal = false; - } +With non-volatile variables there are no guarantees about when the Java Virtual Machine (JVM) reads data from main memory into CPU caches, or writes data from CPU caches to main memory. Let me explain what problems that can cause with an example: -} -The take() method sends a signal which is stored internally in the Semaphore. The release() method waits for a signal. When received the signal flag is cleared again, and the release() method exited. - -Using a semaphore like this you can avoid missed signals. You will call take() instead of notify() and release() instead of wait(). If the call to take() happens before the call to release() the thread calling release() will still know that take() was called, because the signal is stored internally in the signal variable. This is not the case with wait() and notify(). - -The names take() and release() may seem a bit odd when using a semaphore for signaling. The names origin from the use of semaphores as locks, as explained later in this text. In that case the names make more sense. - -Using Semaphores for Signaling +Imagine a situation in which two or more threads have access to a shared object which contains a counter variable declared like this: -Here is a simplified example of two threads signaling each other using a Semaphore: +public class SharedObject { -Semaphore semaphore = new Semaphore(); + public int counter = 0; -SendingThread sender = new SendingThread(semaphore); - -ReceivingThread receiver = new ReceivingThread(semaphore); +} +Thread 1 could read a shared counter variable with the value 0 into its CPU cache, increment it to 1 and not write the changed value back into main memory. Thread 2 could then read the same counter variable from main memory where the value of the variable is still 0, into its own CPU cache. Thread 2 could then also increment the counter to 1, and also not write it back to main memory. Thread 1 and Thread 2 are now practically out of sync. The real value of the shared counter variable should have been 2, but each of the threads has the value 1 for the variable in their CPU caches, and in main memory the value is still 0. It is a mess! Even if the threads eventually write their value for the shared counter variable back to main memory, the value will be wrong. -receiver.start(); -sender.start(); -public class SendingThread { - Semaphore semaphore = null; +By declaring the shared counter variable volatile the JVM guarantees that every read of the variable will always be read from main memory, and that all writes to the variable will always be written back to main memory. Here is how the volatile declaration looks: - public SendingThread(Semaphore semaphore){ - this.semaphore = semaphore; - } +public class SharedObject { - public void run(){ - while(true){ - //do something, then signal - this.semaphore.take(); + public volatile int counter = 0; - } - } -} -public class RecevingThread { - Semaphore semaphore = null; - - public ReceivingThread(Semaphore semaphore){ - this.semaphore = semaphore; - } - - public void run(){ - while(true){ - this.semaphore.release(); - //receive signal, then do something... - } - } } -Counting Semaphore +In some cases simply declaring a variable volatile may be enough to assure that multiple threads accessing the variable see the latest written value. I will get back to which cases volatile is sufficient later. -The Semaphore implementation in the previous section does not count the number of signals sent to it by take() method calls. We can change the Semaphore to do so. This is called a counting semaphore. Here is a simple implementation of a counting semaphore: +In the situation with the two threads reading and writing the same variable, simply declaring the variable volatile is not enough. Thread 1 may read the counter value 0 into a CPU register in CPU 1. At the same time (or right after) Thread 2 may read the counter value 0 into a CPU register in CPU 2. Both threads have read the value directly from main memory. Now both variables increase the value and writes the value back to main memory. They both increment their register version of counter to 1, and both write the value 1 back to main memory. The value should have been 2 after two increments. -public class CountingSemaphore { - private int signals = 0; +The problem with multiple threads that do not see the latest value of a variable because that value has not yet been written back to main memory by another thread, is called a "visibility" problem. The updates of one thread are not visible to other threads. - public synchronized void take() { - this.signals++; - this.notify(); - } +##The Java volatile Guarantee - public synchronized void release() throws InterruptedException{ - while(this.signals == 0) wait(); - this.signals--; - } +Since Java 5 the volatile keyword guarantees more than just the reading and writing of a variable from and to main memory. Actually, the volatile keyword guarantees this: -} -Bounded Semaphore - -The CoutingSemaphore has no upper bound on how many signals it can store. We can change the semaphore implementation to have an upper bound, like this: - -public class BoundedSemaphore { - private int signals = 0; - private int bound = 0; +If Thread A writes to a volatile variable and Thread B subsequently reads the same volatile variable, then all variables visible to Thread A before writing the volatile variable, will also be visible to Thread B. - public BoundedSemaphore(int upperBound){ - this.bound = upperBound; - } +The reading and writing instructions of volatile variables cannot be reordered by the JVM (the JVM may reorder instructions for performance reasons as long as the JVM detects no change in program behaviour from the reordering). Instructions before and after can be reordered, but the volatile read or write cannot be mixed with these instructions. Whatever instructions follow a read or write of a volatile variable are guaranteed to happen after the read or write. +Look at this example: - public synchronized void take() throws InterruptedException{ - while(this.signals == bound) wait(); - this.signals++; - this.notify(); - } +Thread A: + sharedObject.nonVolatile = 123; + sharedObject.counter = sharedObject.counter + 1; - public synchronized void release() throws InterruptedException{ - while(this.signals == 0) wait(); - this.signals--; - this.notify(); - } -} -Notice how the take() method now blocks if the number of signals is equal to the upper bound. Not until a thread has called release() will the thread calling take() be allowed to deliver its signal, if the BoundedSemaphore has reached its upper signal limit. - -Using Semaphores as Locks +Thread B: + int counter = sharedObject.counter; + int nonVolatile = sharedObject.nonVolatile; +Since Thread A writes the non-volatile variable sharedObject.nonVolatile before writing to the volatile sharedObject.counter, then both sharedObject.nonVolatile and sharedObject.counter are written to main memory. -It is possible to use a bounded semaphore as a lock. To do so, set the upper bound to 1, and have the call to take() and release() guard the critical section. Here is an example: +Since Thread B starts by reading the volatile sharedObject.counter, then both the sharedObject.counter and sharedObject.nonVolatile are read in from main memory. -BoundedSemaphore semaphore = new BoundedSemaphore(1); +The reading and writing of the non-volatile variable cannot be reordered to happen before or after the reading and writing of the volatile variable. -... +##When is volatile Enough? -semaphore.take(); +As I have mentioned earlier, if two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use synchronization in that case to guarantee that the reading and writing of the variable is atomic. -try{ - //critical section -} finally { - semaphore.release(); -} -In contrast to the signaling use case the methods take() and release() are now called by the same thread. Since only one thread is allowed to take the semaphore, all other threads calling take() will be blocked until release() is called. The call to release() will never block since there has always been a call to take() first. +But in case one thread reads and writes the value of a volatile variable, and other threads only read the variable, then the reading threads are guaranteed to see the latest value written to the volatile variable. Without making the variable volatile, this would not be guaranteed. -You can also use a bounded semaphore to limit the number of threads allowed into a section of code. For instance, in the example above, what would happen if you set the limit of the BoundedSemaphore to 5? 5 threads would be allowed to enter the critical section at a time. You would have to make sure though, that the thread operations do not conflict for these 5 threads, or you application will fail. +##Performance Considerations of volatile -The relase() method is called from inside a finally-block to make sure it is called even if an exception is thrown from the critical section. +Reading and writing of volatile variables causes the variable to be read or written to main memory. Reading from and writing to main memory is more expensive than accessing the CPU cache. Accessing volatile variables also prevent instruction reordering which is anormal performance enhancement techqniqe. Thus, you should only use volatile variables when you really need to enforce visibility of variables. From c091abd6ac30356a81d38424257d50e456ebd44a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 16 Sep 2014 09:35:03 +0800 Subject: [PATCH 261/524] Published with https://stackedit.io/ --- ...32\204volatile\345\205\263\351\224\256\345\255\227.md" | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 588c4a0..d3315fa 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -4,7 +4,7 @@ The Java volatile keyword is used to mark a Java variable as "being stored in ma Actually, since Java 5 the volatile keyword guarantees more than just that volatile variables are written to and read from main memory. I will explain that in the following sections. -##Java volatile Guarantees Variable Visibility +##volatile保证变量可见性(Java volatile Guarantees Variable Visibility) The Java volatile keyword guarantees visibility of changes to variables across threads. This may sound a bit abstract, so let me elaborate. @@ -36,7 +36,7 @@ In the situation with the two threads reading and writing the same variable, sim The problem with multiple threads that do not see the latest value of a variable because that value has not yet been written back to main memory by another thread, is called a "visibility" problem. The updates of one thread are not visible to other threads. -##The Java volatile Guarantee +##valatile的保证(The Java volatile Guarantee) Since Java 5 the volatile keyword guarantees more than just the reading and writing of a variable from and to main memory. Actually, the volatile keyword guarantees this: @@ -58,13 +58,13 @@ Since Thread B starts by reading the volatile sharedObject.counter, then both th The reading and writing of the non-volatile variable cannot be reordered to happen before or after the reading and writing of the volatile variable. -##When is volatile Enough? +##volatile足够了吗?(When is volatile Enough?) As I have mentioned earlier, if two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use synchronization in that case to guarantee that the reading and writing of the variable is atomic. But in case one thread reads and writes the value of a volatile variable, and other threads only read the variable, then the reading threads are guaranteed to see the latest value written to the volatile variable. Without making the variable volatile, this would not be guaranteed. -##Performance Considerations of volatile +##volatile的性能考虑(Performance Considerations of volatile) Reading and writing of volatile variables causes the variable to be read or written to main memory. Reading from and writing to main memory is more expensive than accessing the CPU cache. Accessing volatile variables also prevent instruction reordering which is anormal performance enhancement techqniqe. Thus, you should only use volatile variables when you really need to enforce visibility of variables. From 66589d05e7d2886b4f7a425fddde9c802c86327b Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 18 Sep 2014 16:05:04 +0800 Subject: [PATCH 262/524] Published with https://stackedit.io/ --- ...7\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 5 +++++ 1 file changed, 5 insertions(+) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index d3315fa..348bdc5 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -4,6 +4,11 @@ The Java volatile keyword is used to mark a Java variable as "being stored in ma Actually, since Java 5 the volatile keyword guarantees more than just that volatile variables are written to and read from main memory. I will explain that in the following sections. +Java的volatile关键字是用来标记一个Java变量作为“被存储在主内存”。更确切地说,这意味着,一个volatile变量的每一个读操作将在电脑的主内存中读取,而不是从CPU高速缓存和每一个写入volatile变量将被写入主内存,而不是仅仅在CPU缓存。 + +事实上,从Java5 volatile关键字保证远远不止这些volatile变量写入,并从主内存中读取。我将解释在下面的章节。 + + ##volatile保证变量可见性(Java volatile Guarantees Variable Visibility) The Java volatile keyword guarantees visibility of changes to variables across threads. This may sound a bit abstract, so let me elaborate. From dbbe6ee61c6671cdb6db71e3bc0c79731b9a0af2 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 18 Sep 2014 16:29:27 +0800 Subject: [PATCH 263/524] Published with https://stackedit.io/ --- ...47\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 348bdc5..5bafbd5 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -1,8 +1,8 @@ #09.Java的volatile关键字 -The Java volatile keyword is used to mark a Java variable as "being stored in main memory". More precisely that means, that every read of a volatile variable will be read from the computer's main memory, and not from the CPU cache, and that every write to a volatile variable will be written to main memory, and not just to the CPU cache. +Java的**volatile**关键字用来标识让变量**像存储在主内存中一样** (The Java volatile keyword is used to mark a Java variable as "being stored in main memory". )。更准确地说,被volatile声明的变量,它们的读操作都是从**主内存**中而不是**CPU缓存**中读取,同时,以及它们的写操作,都会同时写到**主内存**和**CPU缓存**中。 -Actually, since Java 5 the volatile keyword guarantees more than just that volatile variables are written to and read from main memory. I will explain that in the following sections. +实际上,从Java 5开始,volatile关键字不仅仅只是保证变量从主内存中读取和写入。我会在接下来的章节进行详细讲解。 Java的volatile关键字是用来标记一个Java变量作为“被存储在主内存”。更确切地说,这意味着,一个volatile变量的每一个读操作将在电脑的主内存中读取,而不是从CPU高速缓存和每一个写入volatile变量将被写入主内存,而不是仅仅在CPU缓存。 From d1cc3a1fa9c36b4f9470149e181295a90c959bbb Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 18 Sep 2014 17:06:05 +0800 Subject: [PATCH 264/524] Published with https://stackedit.io/ --- ...04volatile\345\205\263\351\224\256\345\255\227.md" | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 5bafbd5..63e2a46 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -4,19 +4,16 @@ Java的**volatile**关键字用来标识让变量**像存储在主内存中一 实际上,从Java 5开始,volatile关键字不仅仅只是保证变量从主内存中读取和写入。我会在接下来的章节进行详细讲解。 -Java的volatile关键字是用来标记一个Java变量作为“被存储在主内存”。更确切地说,这意味着,一个volatile变量的每一个读操作将在电脑的主内存中读取,而不是从CPU高速缓存和每一个写入volatile变量将被写入主内存,而不是仅仅在CPU缓存。 - -事实上,从Java5 volatile关键字保证远远不止这些volatile变量写入,并从主内存中读取。我将解释在下面的章节。 - - ##volatile保证变量可见性(Java volatile Guarantees Variable Visibility) -The Java volatile keyword guarantees visibility of changes to variables across threads. This may sound a bit abstract, so let me elaborate. +Java的volatile关键字保证了**线程间变量的可见性**。这听起来似乎很抽象, 让我来解释一下。 -In a multithreaded application where the threads operate on non-volatile variables, each thread may copy variables from main memory into a CPU cache while working on them, for performance reasons. If your computer contains more than one CPU, each thread may run on a different CPU. That means, that each thread may copy the variables into the CPU cache of different CPUs. This diagram illustrates such a situation: +在多线程的应用程序中,当多个线程对没有volatile关键字声明的变量进行操作时,基于性能考虑,每个线程都会从主内存中拷贝一份变量的值到CPU缓存里。如果你的计算器拥有多个CPU,那么每个线程都有可能使用不同的CPU运行。这意味着,每个线程都有可能拷贝一份数据到各自的CPU缓存中。这种情况如下图所示:  + + With non-volatile variables there are no guarantees about when the Java Virtual Machine (JVM) reads data from main memory into CPU caches, or writes data from CPU caches to main memory. Let me explain what problems that can cause with an example: Imagine a situation in which two or more threads have access to a shared object which contains a counter variable declared like this: From e3041c607f97c18f54d01000284f85a82341aff0 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 18 Sep 2014 17:09:21 +0800 Subject: [PATCH 265/524] Published with https://stackedit.io/ --- ...\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 63e2a46..f81c95e 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -12,9 +12,9 @@ Java的volatile关键字保证了**线程间变量的可见性**。这听起来  +没有使用volatile声明的变量,将不能保证**JVM何时从主内存中读取数据到CPU缓存,以及何时从CPU缓冲中读取数据到内存**。让我解释一下这样会发生什么状况: -With non-volatile variables there are no guarantees about when the Java Virtual Machine (JVM) reads data from main memory into CPU caches, or writes data from CPU caches to main memory. Let me explain what problems that can cause with an example: Imagine a situation in which two or more threads have access to a shared object which contains a counter variable declared like this: From 672b273e2a10c3d22f2f9b5d7b20ca3fbd456aba Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 18 Sep 2014 17:17:19 +0800 Subject: [PATCH 266/524] Published with https://stackedit.io/ --- ...04volatile\345\205\263\351\224\256\345\255\227.md" | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index f81c95e..1199383 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -14,15 +14,16 @@ Java的volatile关键字保证了**线程间变量的可见性**。这听起来 没有使用volatile声明的变量,将不能保证**JVM何时从主内存中读取数据到CPU缓存,以及何时从CPU缓冲中读取数据到内存**。让我解释一下这样会发生什么状况: +想象这样一个场景:多个线程访问同一个共享对象,这个对象包含一个计数器变量: - -Imagine a situation in which two or more threads have access to a shared object which contains a counter variable declared like this: - +```Java public class SharedObject { - public int counter = 0; - } +``` + +线程1读取counter变量值0到CPU缓冲,同时对该变量加1,但并不立即写回主内存。线程2同样读取主内存中的counter变量值0到自己的CPU缓存中,线程2同样对这个值加1,同样也不立即写回主内存。 + Thread 1 could read a shared counter variable with the value 0 into its CPU cache, increment it to 1 and not write the changed value back into main memory. Thread 2 could then read the same counter variable from main memory where the value of the variable is still 0, into its own CPU cache. Thread 2 could then also increment the counter to 1, and also not write it back to main memory. Thread 1 and Thread 2 are now practically out of sync. The real value of the shared counter variable should have been 2, but each of the threads has the value 1 for the variable in their CPU caches, and in main memory the value is still 0. It is a mess! Even if the threads eventually write their value for the shared counter variable back to main memory, the value will be wrong. By declaring the shared counter variable volatile the JVM guarantees that every read of the variable will always be read from main memory, and that all writes to the variable will always be written back to main memory. Here is how the volatile declaration looks: From 1229ef3c784ba30e9de07edcc749fdd04de5fe60 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 18 Sep 2014 17:23:29 +0800 Subject: [PATCH 267/524] Published with https://stackedit.io/ --- ...347\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 1199383..50ca32d 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -22,9 +22,8 @@ public class SharedObject { } ``` -线程1读取counter变量值0到CPU缓冲,同时对该变量加1,但并不立即写回主内存。线程2同样读取主内存中的counter变量值0到自己的CPU缓存中,线程2同样对这个值加1,同样也不立即写回主内存。 +线程1读取counter变量值0到CPU缓存,同时对该变量加1,但并不立即写回主内存。线程2同样读取主内存中的counter变量值0到自己的CPU缓存中,同样对这个值加1,也不立即写回主内存。线程1和线程2实际上并不是同步的(Thread 1 and Thread 2 are now practically out of sync. )。此时,counter的正确值应该为2,而线程1和线程2在CPU缓存的值却是1,而主内存中counter的值目前仍然是0。这种情况是十分混乱的,即使线程将CPU缓存的值写回住内存中,这个值也是错误的。 -Thread 1 could read a shared counter variable with the value 0 into its CPU cache, increment it to 1 and not write the changed value back into main memory. Thread 2 could then read the same counter variable from main memory where the value of the variable is still 0, into its own CPU cache. Thread 2 could then also increment the counter to 1, and also not write it back to main memory. Thread 1 and Thread 2 are now practically out of sync. The real value of the shared counter variable should have been 2, but each of the threads has the value 1 for the variable in their CPU caches, and in main memory the value is still 0. It is a mess! Even if the threads eventually write their value for the shared counter variable back to main memory, the value will be wrong. By declaring the shared counter variable volatile the JVM guarantees that every read of the variable will always be read from main memory, and that all writes to the variable will always be written back to main memory. Here is how the volatile declaration looks: From 13117666bdd84cc44a47d6848101fbdf4f69a004 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 18 Sep 2014 17:27:56 +0800 Subject: [PATCH 268/524] Published with https://stackedit.io/ --- ...204volatile\345\205\263\351\224\256\345\255\227.md" | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 50ca32d..c70a62e 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -24,14 +24,16 @@ public class SharedObject { 线程1读取counter变量值0到CPU缓存,同时对该变量加1,但并不立即写回主内存。线程2同样读取主内存中的counter变量值0到自己的CPU缓存中,同样对这个值加1,也不立即写回主内存。线程1和线程2实际上并不是同步的(Thread 1 and Thread 2 are now practically out of sync. )。此时,counter的正确值应该为2,而线程1和线程2在CPU缓存的值却是1,而主内存中counter的值目前仍然是0。这种情况是十分混乱的,即使线程将CPU缓存的值写回住内存中,这个值也是错误的。 +如果使用**volatile**关键字声明counter变量,JVM将会保证每次读取counter的值都会从主内存中读取,每次对counter变量的修改都会立即写回到主内存。 -By declaring the shared counter variable volatile the JVM guarantees that every read of the variable will always be read from main memory, and that all writes to the variable will always be written back to main memory. Here is how the volatile declaration looks: - +```Java public class SharedObject { - public volatile int counter = 0; - } +``` + + + In some cases simply declaring a variable volatile may be enough to assure that multiple threads accessing the variable see the latest written value. I will get back to which cases volatile is sufficient later. In the situation with the two threads reading and writing the same variable, simply declaring the variable volatile is not enough. Thread 1 may read the counter value 0 into a CPU register in CPU 1. At the same time (or right after) Thread 2 may read the counter value 0 into a CPU register in CPU 2. Both threads have read the value directly from main memory. Now both variables increase the value and writes the value back to main memory. They both increment their register version of counter to 1, and both write the value 1 back to main memory. The value should have been 2 after two increments. From cfdaf15b3866d96264f6ee9f9c08960bc8b1c168 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Thu, 18 Sep 2014 17:44:23 +0800 Subject: [PATCH 269/524] Published with https://stackedit.io/ --- ...347\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index c70a62e..50abfd6 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -31,11 +31,10 @@ public class SharedObject { public volatile int counter = 0; } ``` +In some cases simply declaring a variable volatile may be enough to assure that multiple threads accessing the variable see the latest written value. I will get back to which cases volatile is sufficient later. -In some cases simply declaring a variable volatile may be enough to assure that multiple threads accessing the variable see the latest written value. I will get back to which cases volatile is sufficient later. - In the situation with the two threads reading and writing the same variable, simply declaring the variable volatile is not enough. Thread 1 may read the counter value 0 into a CPU register in CPU 1. At the same time (or right after) Thread 2 may read the counter value 0 into a CPU register in CPU 2. Both threads have read the value directly from main memory. Now both variables increase the value and writes the value back to main memory. They both increment their register version of counter to 1, and both write the value 1 back to main memory. The value should have been 2 after two increments. The problem with multiple threads that do not see the latest value of a variable because that value has not yet been written back to main memory by another thread, is called a "visibility" problem. The updates of one thread are not visible to other threads. From 4d471656b05a2e72974d0b32158959003ef73770 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 09:20:43 +0800 Subject: [PATCH 270/524] Published with https://stackedit.io/ --- ...\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 50abfd6..2e8a466 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -33,7 +33,7 @@ public class SharedObject { ``` In some cases simply declaring a variable volatile may be enough to assure that multiple threads accessing the variable see the latest written value. I will get back to which cases volatile is sufficient later. - +在一些情况下,简单地将变量用volatile声明,已经足够让变量对多线程可见(每次线程读取的都是最新值,以及每次写操作都会立即让其他线程可见)。 In the situation with the two threads reading and writing the same variable, simply declaring the variable volatile is not enough. Thread 1 may read the counter value 0 into a CPU register in CPU 1. At the same time (or right after) Thread 2 may read the counter value 0 into a CPU register in CPU 2. Both threads have read the value directly from main memory. Now both variables increase the value and writes the value back to main memory. They both increment their register version of counter to 1, and both write the value 1 back to main memory. The value should have been 2 after two increments. From 6f4ec0b1aa16adbb5319c5b4f87fde2c7e3b5511 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 09:37:12 +0800 Subject: [PATCH 271/524] Published with https://stackedit.io/ --- ...\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 2e8a466..58eae58 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -24,7 +24,7 @@ public class SharedObject { 线程1读取counter变量值0到CPU缓存,同时对该变量加1,但并不立即写回主内存。线程2同样读取主内存中的counter变量值0到自己的CPU缓存中,同样对这个值加1,也不立即写回主内存。线程1和线程2实际上并不是同步的(Thread 1 and Thread 2 are now practically out of sync. )。此时,counter的正确值应该为2,而线程1和线程2在CPU缓存的值却是1,而主内存中counter的值目前仍然是0。这种情况是十分混乱的,即使线程将CPU缓存的值写回住内存中,这个值也是错误的。 -如果使用**volatile**关键字声明counter变量,JVM将会保证每次读取counter的值都会从主内存中读取,每次对counter变量的修改都会立即写回到主内存。 +如果使用**volatile**关键字声明counter变量,JVM将会保证每次读取counter的值都会从主内存中读取,每次对counter变量的修改都会立即写回到主内存。 ```Java public class SharedObject { @@ -33,7 +33,9 @@ public class SharedObject { ``` In some cases simply declaring a variable volatile may be enough to assure that multiple threads accessing the variable see the latest written value. I will get back to which cases volatile is sufficient later. -在一些情况下,简单地将变量用volatile声明,已经足够让变量对多线程可见(每次线程读取的都是最新值,以及每次写操作都会立即让其他线程可见)。 +在一些情况下,简单地用volatile声明变量,已经足够让变量对多线程可见(每次线程读取的都是最新值,以及每次写操作都会立即让其他线程可见)。 + +然而,在另一些情况下,简单地用volatile声明变量,并不能保证让变量对多线程可见。线程1读取counter的值0到CPU1的寄存器中,于此同时(或紧接着)线程2读取counter的值0到CPU2的寄存器中。两个线程都是直接从主内存中读取counter的值。然后,两个线程分别对counter的值加1,并写回主内存中。经过加1后,两个寄存器中的值都是1,并且把这个值写回主内存中。然而counter的正确值应该为2 。 In the situation with the two threads reading and writing the same variable, simply declaring the variable volatile is not enough. Thread 1 may read the counter value 0 into a CPU register in CPU 1. At the same time (or right after) Thread 2 may read the counter value 0 into a CPU register in CPU 2. Both threads have read the value directly from main memory. Now both variables increase the value and writes the value back to main memory. They both increment their register version of counter to 1, and both write the value 1 back to main memory. The value should have been 2 after two increments. From 4c908f80933ec04d89796e3d4e583635941af4fc Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 09:41:09 +0800 Subject: [PATCH 272/524] Published with https://stackedit.io/ --- ...47\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 58eae58..ad3bfac 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -33,9 +33,9 @@ public class SharedObject { ``` In some cases simply declaring a variable volatile may be enough to assure that multiple threads accessing the variable see the latest written value. I will get back to which cases volatile is sufficient later. -在一些情况下,简单地用volatile声明变量,已经足够让变量对多线程可见(每次线程读取的都是最新值,以及每次写操作都会立即让其他线程可见)。 +在一些情况下,简单地用volatile声明变量,也许已经足够让多个线程每次读取的都是变量的最新值。 -然而,在另一些情况下,简单地用volatile声明变量,并不能保证让变量对多线程可见。线程1读取counter的值0到CPU1的寄存器中,于此同时(或紧接着)线程2读取counter的值0到CPU2的寄存器中。两个线程都是直接从主内存中读取counter的值。然后,两个线程分别对counter的值加1,并写回主内存中。经过加1后,两个寄存器中的值都是1,并且把这个值写回主内存中。然而counter的正确值应该为2 。 +然而,在另一些情况下,当两个线程都对变量读取和写入时,volatile并不足够。线程1读取counter的值0到CPU1的寄存器中,于此同时(或紧接着)线程2读取counter的值0到CPU2的寄存器中。两个线程都是直接从主内存中读取counter的值。然后,两个线程分别对counter的值加1,并写回主内存中。经过加1后,两个寄存器中的值都是1,并且把这个值写回主内存中。然而counter的正确值应该为2 。 In the situation with the two threads reading and writing the same variable, simply declaring the variable volatile is not enough. Thread 1 may read the counter value 0 into a CPU register in CPU 1. At the same time (or right after) Thread 2 may read the counter value 0 into a CPU register in CPU 2. Both threads have read the value directly from main memory. Now both variables increase the value and writes the value back to main memory. They both increment their register version of counter to 1, and both write the value 1 back to main memory. The value should have been 2 after two increments. From 3f9dd7c3766db5427f28a274fb2769ff0c32ce94 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 09:45:28 +0800 Subject: [PATCH 273/524] Published with https://stackedit.io/ --- ...7\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index ad3bfac..a27b809 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -31,12 +31,15 @@ public class SharedObject { public volatile int counter = 0; } ``` -In some cases simply declaring a variable volatile may be enough to assure that multiple threads accessing the variable see the latest written value. I will get back to which cases volatile is sufficient later. 在一些情况下,简单地用volatile声明变量,也许已经足够让多个线程每次读取的都是变量的最新值。 然而,在另一些情况下,当两个线程都对变量读取和写入时,volatile并不足够。线程1读取counter的值0到CPU1的寄存器中,于此同时(或紧接着)线程2读取counter的值0到CPU2的寄存器中。两个线程都是直接从主内存中读取counter的值。然后,两个线程分别对counter的值加1,并写回主内存中。经过加1后,两个寄存器中的值都是1,并且把这个值写回主内存中。然而counter的正确值应该为2 。 +上述问题中,多个线程并没有读取到变量的最新值,是因为其他线程还没将寄存器的值写回主内存,这就是“** 可见性**”问题。一个线程的更新对其他线程不可见。 + +In some cases simply declaring a variable volatile may be enough to assure that multiple threads accessing the variable see the latest written value. I will get back to which cases volatile is sufficient later. + In the situation with the two threads reading and writing the same variable, simply declaring the variable volatile is not enough. Thread 1 may read the counter value 0 into a CPU register in CPU 1. At the same time (or right after) Thread 2 may read the counter value 0 into a CPU register in CPU 2. Both threads have read the value directly from main memory. Now both variables increase the value and writes the value back to main memory. They both increment their register version of counter to 1, and both write the value 1 back to main memory. The value should have been 2 after two increments. The problem with multiple threads that do not see the latest value of a variable because that value has not yet been written back to main memory by another thread, is called a "visibility" problem. The updates of one thread are not visible to other threads. From d1d1a06da84fd246833271e2118e07f9cdcbc523 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 09:50:45 +0800 Subject: [PATCH 274/524] Published with https://stackedit.io/ --- ...232\204volatile\345\205\263\351\224\256\345\255\227.md" | 7 +++++++ 1 file changed, 7 insertions(+) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index a27b809..28c8ace 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -46,6 +46,10 @@ The problem with multiple threads that do not see the latest value of a variable ##valatile的保证(The Java volatile Guarantee) +从Java 5之后,volatile关键字不仅仅只是保证每次都是从主内存中读取和写入数据。实际上volatile关键字保证: + +> 如果线程A对volatile变量进行修改,紧接着线程B对这个变量进行读取, + Since Java 5 the volatile keyword guarantees more than just the reading and writing of a variable from and to main memory. Actually, the volatile keyword guarantees this: If Thread A writes to a volatile variable and Thread B subsequently reads the same volatile variable, then all variables visible to Thread A before writing the volatile variable, will also be visible to Thread B. @@ -53,6 +57,7 @@ If Thread A writes to a volatile variable and Thread B subsequently reads the sa The reading and writing instructions of volatile variables cannot be reordered by the JVM (the JVM may reorder instructions for performance reasons as long as the JVM detects no change in program behaviour from the reordering). Instructions before and after can be reordered, but the volatile read or write cannot be mixed with these instructions. Whatever instructions follow a read or write of a volatile variable are guaranteed to happen after the read or write. Look at this example: +```Java Thread A: sharedObject.nonVolatile = 123; sharedObject.counter = sharedObject.counter + 1; @@ -60,6 +65,8 @@ Thread A: Thread B: int counter = sharedObject.counter; int nonVolatile = sharedObject.nonVolatile; +``` + Since Thread A writes the non-volatile variable sharedObject.nonVolatile before writing to the volatile sharedObject.counter, then both sharedObject.nonVolatile and sharedObject.counter are written to main memory. Since Thread B starts by reading the volatile sharedObject.counter, then both the sharedObject.counter and sharedObject.nonVolatile are read in from main memory. From 166efaaae04907a7025c00c7c29a9aee6697aa60 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 09:56:53 +0800 Subject: [PATCH 275/524] Published with https://stackedit.io/ --- ...32\204volatile\345\205\263\351\224\256\345\255\227.md" | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 28c8ace..bbcde8e 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -1,5 +1,7 @@ #09.Java的volatile关键字 +未完,有疑惑,待续! + Java的**volatile**关键字用来标识让变量**像存储在主内存中一样** (The Java volatile keyword is used to mark a Java variable as "being stored in main memory". )。更准确地说,被volatile声明的变量,它们的读操作都是从**主内存**中而不是**CPU缓存**中读取,同时,以及它们的写操作,都会同时写到**主内存**和**CPU缓存**中。 实际上,从Java 5开始,volatile关键字不仅仅只是保证变量从主内存中读取和写入。我会在接下来的章节进行详细讲解。 @@ -48,11 +50,7 @@ The problem with multiple threads that do not see the latest value of a variable 从Java 5之后,volatile关键字不仅仅只是保证每次都是从主内存中读取和写入数据。实际上volatile关键字保证: -> 如果线程A对volatile变量进行修改,紧接着线程B对这个变量进行读取, - -Since Java 5 the volatile keyword guarantees more than just the reading and writing of a variable from and to main memory. Actually, the volatile keyword guarantees this: - -If Thread A writes to a volatile variable and Thread B subsequently reads the same volatile variable, then all variables visible to Thread A before writing the volatile variable, will also be visible to Thread B. +> If Thread A writes to a volatile variable and Thread B subsequently reads the same volatile variable, then all variables visible to Thread A before writing the volatile variable, will also be visible to Thread B. The reading and writing instructions of volatile variables cannot be reordered by the JVM (the JVM may reorder instructions for performance reasons as long as the JVM detects no change in program behaviour from the reordering). Instructions before and after can be reordered, but the volatile read or write cannot be mixed with these instructions. Whatever instructions follow a read or write of a volatile variable are guaranteed to happen after the read or write. Look at this example: From 4e8ab0cbaac2cb16c098a67050d32443d9cb586a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 10:01:43 +0800 Subject: [PATCH 276/524] Published with https://stackedit.io/ --- ...7\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 5 +++++ 1 file changed, 5 insertions(+) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index bbcde8e..5534dd9 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -73,6 +73,11 @@ The reading and writing of the non-volatile variable cannot be reordered to happ ##volatile足够了吗?(When is volatile Enough?) +正如前面我所提到的,当两个线程都对共享变量进行读取和写入时,使用volatile关键字是不足够的。你需要 +对变量的读取和写入进行同步,保证这些操作都是原子性的。 + + + As I have mentioned earlier, if two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use synchronization in that case to guarantee that the reading and writing of the variable is atomic. But in case one thread reads and writes the value of a volatile variable, and other threads only read the variable, then the reading threads are guaranteed to see the latest value written to the volatile variable. Without making the variable volatile, this would not be guaranteed. From 3783cca7f95a384997ece04dc7fc616354c978ad Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 10:04:06 +0800 Subject: [PATCH 277/524] Published with https://stackedit.io/ --- ...\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 5534dd9..fc2c43e 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -76,7 +76,7 @@ The reading and writing of the non-volatile variable cannot be reordered to happ 正如前面我所提到的,当两个线程都对共享变量进行读取和写入时,使用volatile关键字是不足够的。你需要 对变量的读取和写入进行同步,保证这些操作都是原子性的。 - +当如果只有一个线程对变量进行读取和写入,而其它线程都只对变量进行读取,那么就可以保证读线程每次读到的都是volatile变量的最新值。如果没有volatile关键字,这些都是不可以保证的。 As I have mentioned earlier, if two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use synchronization in that case to guarantee that the reading and writing of the variable is atomic. From 03049be504cf35ef7b2cbb489f41e2e355a206cd Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 10:08:31 +0800 Subject: [PATCH 278/524] Published with https://stackedit.io/ --- ...\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index fc2c43e..68a6eb8 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -84,5 +84,7 @@ But in case one thread reads and writes the value of a volatile variable, and ot ##volatile的性能考虑(Performance Considerations of volatile) +volatile关键字保证变量的读取和写入都会在主内存中进行。相比从CPU缓存中读取和写入数据,在主内存中读取和写入数据是相对比较消耗性能的。 + Reading and writing of volatile variables causes the variable to be read or written to main memory. Reading from and writing to main memory is more expensive than accessing the CPU cache. Accessing volatile variables also prevent instruction reordering which is anormal performance enhancement techqniqe. Thus, you should only use volatile variables when you really need to enforce visibility of variables. From 73263be006bf23b433743d14ba09dac4991327aa Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 10:12:35 +0800 Subject: [PATCH 279/524] Published with https://stackedit.io/ --- ...\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" index 68a6eb8..4cf1bfb 100644 --- "a/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/Java-Concurrency/09.Java\347\232\204volatile\345\205\263\351\224\256\345\255\227.md" @@ -84,7 +84,7 @@ But in case one thread reads and writes the value of a volatile variable, and ot ##volatile的性能考虑(Performance Considerations of volatile) -volatile关键字保证变量的读取和写入都会在主内存中进行。相比从CPU缓存中读取和写入数据,在主内存中读取和写入数据是相对比较消耗性能的。 +volatile关键字保证变量的读取和写入都会在主内存中进行。相比从CPU缓存中读取和写入数据,在主内存中读取和写入数据是相对比较消耗性能的。volatile关键字会阻止指令重排(指令重排是很常见的用于增强性能的技术)。因此,只有当真正需要让变量强制可见时才使用volatile关键字。 Reading and writing of volatile variables causes the variable to be read or written to main memory. Reading from and writing to main memory is more expensive than accessing the CPU cache. Accessing volatile variables also prevent instruction reordering which is anormal performance enhancement techqniqe. Thus, you should only use volatile variables when you really need to enforce visibility of variables. From b4e70d431296d5e6a5106604e8e66a0f7c76c8b4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 10:14:24 +0800 Subject: [PATCH 280/524] Published with https://stackedit.io/ From e1cf2a3b7adb57b3e45d9bafaabe27dcc597e88d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 14:27:30 +0800 Subject: [PATCH 281/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 122 +++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 "Java-Security/01.\351\224\201.md" diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" new file mode 100644 index 0000000..21c5b6a --- /dev/null +++ "b/Java-Security/01.\351\224\201.md" @@ -0,0 +1,122 @@ +#锁 + +##Do not synchronize on objects that may be reused + +Misuse of synchronization primitives is a common source of concurrency issues. Synchronizing on objects that may be reused can result in deadlock and nondeterministic behavior. Consequently, programs must never synchronize on objects that may be reused. +Noncompliant Code Example (Boolean Lock Object) +This noncompliant code example synchronizes on a Boolean lock object. + +``` +private final Boolean initialized = Boolean.FALSE; + +public void doSomething() { + synchronized (initialized) { + // ... + } +} +``` + +The Boolean type is unsuitable for locking purposes because it allows only two values: true and false. Boolean literals containing the same value share unique instances of the Boolean class in the Java Virtual Machine (JVM). In this example, initialized refers to the instance corresponding to the value Boolean.FALSE. If any other code were to inadvertently synchronize on a Boolean literal with this value, the lock instance would be reused and the system could become unresponsive or could deadlock. +Noncompliant Code Example (Boxed Primitive) +This noncompliant code example locks on a boxed Integer object. +private int count = 0; +private final Integer Lock = count; // Boxed primitive Lock is shared + +public void doSomething() { + synchronized (Lock) { + count++; + // ... + } +} +Boxed types may use the same instance for a range of integer values; consequently, they suffer from the same reuse problem as Boolean constants. The wrapper object are reused when the value can be represented as a byte; JVM implementations are also permitted to reuse wrapper objects for larger ranges of values. While use of the intrinsic lock associated with the boxed Integer wrapper object is insecure; instances of the Integer object constructed using the new operator (new Integer(value)) are unique and not reused. In general, locks on any data type that contains a boxed value are insecure. +Compliant Solution (Integer) +This compliant solution locks on a nonboxed Integer, using a variant of the private lock object idiom. The doSomething() method synchronizes using the intrinsic lock of the Integer instance, Lock. +private int count = 0; +private final Integer Lock = new Integer(count); + +public void doSomething() { + synchronized (Lock) { + count++; + // ... + } +} +When explicitly constructed, an Integer object has a unique reference and its own intrinsic lock that is distinct not only from other Integer objects, but also from boxed integers that have the same value. While this is an acceptable solution, it can cause maintenance problems because developers can incorrectly assume that boxed integers are also appropriate lock objects. A more appropriate solution is to synchronize on a private final lock object as described in the final compliant solution for this rule. +Noncompliant Code Example (Interned String Object) +This noncompliant code example locks on an interned String object. +private final String lock = new String("LOCK").intern(); + +public void doSomething() { + synchronized (lock) { + // ... + } +} +According to the Java API class java.lang.String documentation [API 2006]: +When the intern() method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. +Consequently, an interned String object behaves like a global variable in the JVM. As demonstrated in this noncompliant code example, even when every instance of an object maintains its own lock field, the fields all refer to a common String constant. Locking on String constants has the same reuse problem as locking on Boolean constants. +Additionally, hostile code from any other package can exploit this vulnerability, if the class is accessible. See rule LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code for more information. +Noncompliant Code Example (String Literal) +This noncompliant code example locks on a final String literal. +// This bug was found in jetty-6.1.3 BoundedThreadPool +private final String lock = "LOCK"; + +public void doSomething() { + synchronized (lock) { + // ... + } +} +String literals are constant and are automatically interned. Consequently, this example suffers from the same pitfalls as the preceding noncompliant code example. +Compliant Solution (String Instance) +This compliant solution locks on a noninterned String instance. +private final String lock = new String("LOCK"); + +public void doSomething() { + synchronized (lock) { + // ... + } +} +A String instance differs from a String literal. The instance has a unique reference and its own intrinsic lock that is distinct from other String object instances or literals. Nevertheless, a better approach is to synchronize on a private final lock object, as shown in the following compliant solution. +Compliant Solution (Private Final Lock Object) +This compliant solution synchronizes on a private final lock object. This is one of the few cases in which a java.lang.Object instance is useful. +private final Object lock = new Object(); + +public void doSomething() { + synchronized (lock) { + // ... + } +} +For more information on using an Object as a lock, see rule LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code. +Risk Assessment +A significant number of concurrency vulnerabilities arise from locking on the wrong kind of object. It is important to consider the properties of the lock object rather than simply scavenging for objects on which to synchronize. +Rule +Severity +Likelihood +Remediation Cost +Priority +Level +LCK01-J +medium +probable +medium +P8 +L2 +Automated Detection +Some static analysis tools can detect violations of this rule. +Tool +Version +Checker +Description +ThreadSafe 1.3 +CCE_CC_REUSEDOBJ_SYNC +Implemented +Bibliography +[API 2006] +Class String, Collections +[Findbugs 2008] + +[Miller 2009] +Locking +[Pugh 2008] +Synchronization +[Tutorials 2008] +Wrapper Implementations + \ No newline at end of file From 6b598b57ad417ecfcef00592ca3b7c88dcf467e0 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 14:28:02 +0800 Subject: [PATCH 282/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 21c5b6a..1b84b86 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -1,9 +1,9 @@ -#锁 +#01.锁 ##Do not synchronize on objects that may be reused Misuse of synchronization primitives is a common source of concurrency issues. Synchronizing on objects that may be reused can result in deadlock and nondeterministic behavior. Consequently, programs must never synchronize on objects that may be reused. -Noncompliant Code Example (Boolean Lock Object) +Noncompliant Code Example (Boolean Lock Object)01. This noncompliant code example synchronizes on a Boolean lock object. ``` From d02b65e63ff331a2da1ec6ff56b091588495c647 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 14:33:37 +0800 Subject: [PATCH 283/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 1b84b86..93b45da 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -1,6 +1,6 @@ #01.锁 -##Do not synchronize on objects that may be reused +##不要在可重用的对象上加锁 Misuse of synchronization primitives is a common source of concurrency issues. Synchronizing on objects that may be reused can result in deadlock and nondeterministic behavior. Consequently, programs must never synchronize on objects that may be reused. Noncompliant Code Example (Boolean Lock Object)01. @@ -8,7 +8,6 @@ This noncompliant code example synchronizes on a Boolean lock object. ``` private final Boolean initialized = Boolean.FALSE; - public void doSomething() { synchronized (initialized) { // ... @@ -119,4 +118,9 @@ Locking Synchronization [Tutorials 2008] Wrapper Implementations + + +---------- + + \ No newline at end of file From 76e719698e7e68792277c106872eb4635cba2fe0 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 15:00:52 +0800 Subject: [PATCH 284/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 93b45da..2264052 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -2,9 +2,7 @@ ##不要在可重用的对象上加锁 -Misuse of synchronization primitives is a common source of concurrency issues. Synchronizing on objects that may be reused can result in deadlock and nondeterministic behavior. Consequently, programs must never synchronize on objects that may be reused. -Noncompliant Code Example (Boolean Lock Object)01. -This noncompliant code example synchronizes on a Boolean lock object. +不要在可重用的对象上加锁,如果你这样做了,可能导致死锁或其他不可预测的行为。例如下面这个例子: ``` private final Boolean initialized = Boolean.FALSE; @@ -15,12 +13,34 @@ public void doSomething() { } ``` +在这个例子里,Boolean类型并不适合加锁。Boolean.TRUE或Boolean.FALSE都是指向同一个Boolean实例对象。因此,假如其他线程也在Boolean类型上加锁,则可能导致死锁或其他不预测的行为。 + +同样的例子,还有Integer类型,String字面量: + +``` +private final Integer lock = new Integer(10); +public void doSomething() { + synchronized (lock) { + // ... + } +} +``` + +``` +private final String lock = "lock"; +public void doSomething() { + synchronized (lock) { + // ... + } +} +``` + + The Boolean type is unsuitable for locking purposes because it allows only two values: true and false. Boolean literals containing the same value share unique instances of the Boolean class in the Java Virtual Machine (JVM). In this example, initialized refers to the instance corresponding to the value Boolean.FALSE. If any other code were to inadvertently synchronize on a Boolean literal with this value, the lock instance would be reused and the system could become unresponsive or could deadlock. Noncompliant Code Example (Boxed Primitive) This noncompliant code example locks on a boxed Integer object. private int count = 0; private final Integer Lock = count; // Boxed primitive Lock is shared - public void doSomething() { synchronized (Lock) { count++; From 5bda3d8d70d7c6d9e6cc1eeeebb8ca89f1d340a6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 15:01:43 +0800 Subject: [PATCH 285/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 2264052..a5bbcd1 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -4,10 +4,10 @@ 不要在可重用的对象上加锁,如果你这样做了,可能导致死锁或其他不可预测的行为。例如下面这个例子: -``` -private final Boolean initialized = Boolean.FALSE; +```Java +private final Boolean lock= Boolean.FALSE; public void doSomething() { - synchronized (initialized) { + synchronized (lock) { // ... } } @@ -17,7 +17,7 @@ public void doSomething() { 同样的例子,还有Integer类型,String字面量: -``` +```Java private final Integer lock = new Integer(10); public void doSomething() { synchronized (lock) { @@ -26,7 +26,7 @@ public void doSomething() { } ``` -``` +```Java private final String lock = "lock"; public void doSomething() { synchronized (lock) { From af3c4008b340831c24c64e69375bf6fa342fa431 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 15:45:33 +0800 Subject: [PATCH 286/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index a5bbcd1..141e119 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -2,7 +2,9 @@ ##不要在可重用的对象上加锁 -不要在可重用的对象上加锁,如果你这样做了,可能导致死锁或其他不可预测的行为。例如下面这个例子: +不要在可重用的对象上加锁,如果你这样做了,可能导致死锁或其他不可预测的行为。 + +###不合规的代码(Boolean类型锁) ```Java private final Boolean lock= Boolean.FALSE; @@ -26,6 +28,8 @@ public void doSomething() { } ``` + + ```Java private final String lock = "lock"; public void doSomething() { From d5b29e571b26434cd9899afdd1dbea3105a2fe18 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 15:46:09 +0800 Subject: [PATCH 287/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 141e119..0e204ce 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -4,7 +4,7 @@ 不要在可重用的对象上加锁,如果你这样做了,可能导致死锁或其他不可预测的行为。 -###不合规的代码(Boolean类型锁) +####不合规的代码(Boolean类型锁) ```Java private final Boolean lock= Boolean.FALSE; From 1810a1c90a08ae8f27e4cbdde303f22e3e6913c5 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 15:47:17 +0800 Subject: [PATCH 288/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 0e204ce..141e119 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -4,7 +4,7 @@ 不要在可重用的对象上加锁,如果你这样做了,可能导致死锁或其他不可预测的行为。 -####不合规的代码(Boolean类型锁) +###不合规的代码(Boolean类型锁) ```Java private final Boolean lock= Boolean.FALSE; From 734923b9701346a88113571d4725f70446155152 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 16:00:19 +0800 Subject: [PATCH 289/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 141e119..ae02670 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -4,7 +4,9 @@ 不要在可重用的对象上加锁,如果你这样做了,可能导致死锁或其他不可预测的行为。 -###不合规的代码(Boolean类型锁) +####不合规的代码(Boolean类型锁) + +下面的代码在Boolean类型上加锁: ```Java private final Boolean lock= Boolean.FALSE; @@ -15,6 +17,10 @@ public void doSomething() { } ``` +Boolean类型对象并不适合加锁,因为它只有两个值:`true`和`false`。在JVM中,Boolean类型的两个字面量值都分别都指向同一个共享对象。在这里例子中,lock指向JVM中的一个Boolean.FALSE实例,而这个实例的所有线程共享的。如果有其他的线程不注意地也使用了Boolean.FALSE进行加锁,就可能导致死锁或不可预测的行为。 + + + 在这个例子里,Boolean类型并不适合加锁。Boolean.TRUE或Boolean.FALSE都是指向同一个Boolean实例对象。因此,假如其他线程也在Boolean类型上加锁,则可能导致死锁或其他不预测的行为。 同样的例子,还有Integer类型,String字面量: From 5dca9ff3798ce0343808512bc5622ac82371c2a5 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 16:02:12 +0800 Subject: [PATCH 290/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 33 +++++------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index ae02670..762cd20 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -19,44 +19,21 @@ public void doSomething() { Boolean类型对象并不适合加锁,因为它只有两个值:`true`和`false`。在JVM中,Boolean类型的两个字面量值都分别都指向同一个共享对象。在这里例子中,lock指向JVM中的一个Boolean.FALSE实例,而这个实例的所有线程共享的。如果有其他的线程不注意地也使用了Boolean.FALSE进行加锁,就可能导致死锁或不可预测的行为。 +####不合规的代码(Integer的自动装箱) - -在这个例子里,Boolean类型并不适合加锁。Boolean.TRUE或Boolean.FALSE都是指向同一个Boolean实例对象。因此,假如其他线程也在Boolean类型上加锁,则可能导致死锁或其他不预测的行为。 - -同样的例子,还有Integer类型,String字面量: - -```Java -private final Integer lock = new Integer(10); -public void doSomething() { - synchronized (lock) { - // ... - } -} -``` - - +This noncompliant code example locks on a boxed Integer object. ```Java -private final String lock = "lock"; +private int count = 0; +private final Integer lock = 0; // Boxed primitive lock is shared public void doSomething() { synchronized (lock) { + count++; // ... } } ``` - -The Boolean type is unsuitable for locking purposes because it allows only two values: true and false. Boolean literals containing the same value share unique instances of the Boolean class in the Java Virtual Machine (JVM). In this example, initialized refers to the instance corresponding to the value Boolean.FALSE. If any other code were to inadvertently synchronize on a Boolean literal with this value, the lock instance would be reused and the system could become unresponsive or could deadlock. -Noncompliant Code Example (Boxed Primitive) -This noncompliant code example locks on a boxed Integer object. -private int count = 0; -private final Integer Lock = count; // Boxed primitive Lock is shared -public void doSomething() { - synchronized (Lock) { - count++; - // ... - } -} Boxed types may use the same instance for a range of integer values; consequently, they suffer from the same reuse problem as Boolean constants. The wrapper object are reused when the value can be represented as a byte; JVM implementations are also permitted to reuse wrapper objects for larger ranges of values. While use of the intrinsic lock associated with the boxed Integer wrapper object is insecure; instances of the Integer object constructed using the new operator (new Integer(value)) are unique and not reused. In general, locks on any data type that contains a boxed value are insecure. Compliant Solution (Integer) This compliant solution locks on a nonboxed Integer, using a variant of the private lock object idiom. The doSomething() method synchronizes using the intrinsic lock of the Integer instance, Lock. From 5611f36f57ce0a622587ee13eb889a86e9280e66 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 16:04:47 +0800 Subject: [PATCH 291/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 762cd20..38476e8 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -21,7 +21,7 @@ Boolean类型对象并不适合加锁,因为它只有两个值:`true`和`fal ####不合规的代码(Integer的自动装箱) -This noncompliant code example locks on a boxed Integer object. +这个例子中的不合规代码在自动装箱的Integer类型上加锁: ```Java private int count = 0; @@ -34,6 +34,8 @@ public void doSomething() { } ``` + + Boxed types may use the same instance for a range of integer values; consequently, they suffer from the same reuse problem as Boolean constants. The wrapper object are reused when the value can be represented as a byte; JVM implementations are also permitted to reuse wrapper objects for larger ranges of values. While use of the intrinsic lock associated with the boxed Integer wrapper object is insecure; instances of the Integer object constructed using the new operator (new Integer(value)) are unique and not reused. In general, locks on any data type that contains a boxed value are insecure. Compliant Solution (Integer) This compliant solution locks on a nonboxed Integer, using a variant of the private lock object idiom. The doSomething() method synchronizes using the intrinsic lock of the Integer instance, Lock. From 7c3d51122e2d99f931c90412c8cfdd701fbf930b Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 16:06:28 +0800 Subject: [PATCH 292/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 38476e8..b2a2337 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -24,7 +24,6 @@ Boolean类型对象并不适合加锁,因为它只有两个值:`true`和`fal 这个例子中的不合规代码在自动装箱的Integer类型上加锁: ```Java -private int count = 0; private final Integer lock = 0; // Boxed primitive lock is shared public void doSomething() { synchronized (lock) { @@ -34,7 +33,7 @@ public void doSomething() { } ``` - + 自动装箱的Integer对象,在一定范围内是共享的( 这个范围是-128到127)。 Boxed types may use the same instance for a range of integer values; consequently, they suffer from the same reuse problem as Boolean constants. The wrapper object are reused when the value can be represented as a byte; JVM implementations are also permitted to reuse wrapper objects for larger ranges of values. While use of the intrinsic lock associated with the boxed Integer wrapper object is insecure; instances of the Integer object constructed using the new operator (new Integer(value)) are unique and not reused. In general, locks on any data type that contains a boxed value are insecure. Compliant Solution (Integer) From 7ce223519e9737f5e06846f9426f08fa424b4c7a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 16:26:52 +0800 Subject: [PATCH 293/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index b2a2337..c5e88f6 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -33,10 +33,12 @@ public void doSomething() { } ``` - 自动装箱的Integer对象,在一定范围内是共享的( 这个范围是-128到127)。 +自动装箱的Integer对象,在一定范围内是共享的( 这个范围是-128到127),因此,这会导致跟Boolean常量一样的问题。JVM的常量池中缓存了Integer(-128)到Integer(127)这个范围的Integer对象,在这个范围内的自动装箱Integer对象,都是从这个常量池中共享这些对象。有一些JVM实现也允许大于这个范围的Integer常量池。所以,在自动装箱的对象上加锁是不安全的。而使用`new Integer(value)`创建的Integer实例对象是不共享的。**一般来说,在自动装箱的数据类型上加锁都是不可取和不安全的。** + +####解决方案(Integer) + + -Boxed types may use the same instance for a range of integer values; consequently, they suffer from the same reuse problem as Boolean constants. The wrapper object are reused when the value can be represented as a byte; JVM implementations are also permitted to reuse wrapper objects for larger ranges of values. While use of the intrinsic lock associated with the boxed Integer wrapper object is insecure; instances of the Integer object constructed using the new operator (new Integer(value)) are unique and not reused. In general, locks on any data type that contains a boxed value are insecure. -Compliant Solution (Integer) This compliant solution locks on a nonboxed Integer, using a variant of the private lock object idiom. The doSomething() method synchronizes using the intrinsic lock of the Integer instance, Lock. private int count = 0; private final Integer Lock = new Integer(count); From dacc92c9ef61f63938ecc7f0aee4d7442d3c9ba2 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 16:34:30 +0800 Subject: [PATCH 294/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index c5e88f6..ca1a4ff 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -24,7 +24,8 @@ Boolean类型对象并不适合加锁,因为它只有两个值:`true`和`fal 这个例子中的不合规代码在自动装箱的Integer类型上加锁: ```Java -private final Integer lock = 0; // Boxed primitive lock is shared +private int = 0; +private final Integer lock = count; // Boxed primitive lock is shared public void doSomething() { synchronized (lock) { count++; @@ -37,18 +38,22 @@ public void doSomething() { ####解决方案(Integer) +上面例子的解决方法就是在非装箱的Integer对象上加锁。如下面的代码所示: - -This compliant solution locks on a nonboxed Integer, using a variant of the private lock object idiom. The doSomething() method synchronizes using the intrinsic lock of the Integer instance, Lock. +```Java private int count = 0; -private final Integer Lock = new Integer(count); +private final Integer lock = new Integer(count); public void doSomething() { - synchronized (Lock) { + synchronized (lock) { count++; // ... } } +``` + + + When explicitly constructed, an Integer object has a unique reference and its own intrinsic lock that is distinct not only from other Integer objects, but also from boxed integers that have the same value. While this is an acceptable solution, it can cause maintenance problems because developers can incorrectly assume that boxed integers are also appropriate lock objects. A more appropriate solution is to synchronize on a private final lock object as described in the final compliant solution for this rule. Noncompliant Code Example (Interned String Object) This noncompliant code example locks on an interned String object. From c22e62e7c826c37f8fddb92ca09d80b237e40da7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 16:45:44 +0800 Subject: [PATCH 295/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index ca1a4ff..cfa116a 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -19,7 +19,7 @@ public void doSomething() { Boolean类型对象并不适合加锁,因为它只有两个值:`true`和`false`。在JVM中,Boolean类型的两个字面量值都分别都指向同一个共享对象。在这里例子中,lock指向JVM中的一个Boolean.FALSE实例,而这个实例的所有线程共享的。如果有其他的线程不注意地也使用了Boolean.FALSE进行加锁,就可能导致死锁或不可预测的行为。 -####不合规的代码(Integer的自动装箱) +####不合规的代码示例(Integer的自动装箱) 这个例子中的不合规代码在自动装箱的Integer类型上加锁: @@ -51,21 +51,25 @@ public void doSomething() { } } ``` +当使用构造方法时,会创建独立的Integer对象,而不会使用常量池中共享的Intege对象。这是一个可接受的解决方法,但这会导致维护问题,开发人员会错误地认为使用自动装箱的Integer也是可以的。更好的解决方法就是`new Object()`对象,最后一个例子会详细介绍。 +####不合规的代码示例(new String("lock").intern()) +下面是一个不合规的代码示例: -When explicitly constructed, an Integer object has a unique reference and its own intrinsic lock that is distinct not only from other Integer objects, but also from boxed integers that have the same value. While this is an acceptable solution, it can cause maintenance problems because developers can incorrectly assume that boxed integers are also appropriate lock objects. A more appropriate solution is to synchronize on a private final lock object as described in the final compliant solution for this rule. -Noncompliant Code Example (Interned String Object) -This noncompliant code example locks on an interned String object. +```Java private final String lock = new String("LOCK").intern(); - public void doSomething() { synchronized (lock) { // ... } } -According to the Java API class java.lang.String documentation [API 2006]: -When the intern() method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. +``` + +Java API对java.lang.String类的inern()方法解释如下: + +>When the intern() method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. + Consequently, an interned String object behaves like a global variable in the JVM. As demonstrated in this noncompliant code example, even when every instance of an object maintains its own lock field, the fields all refer to a common String constant. Locking on String constants has the same reuse problem as locking on Boolean constants. Additionally, hostile code from any other package can exploit this vulnerability, if the class is accessible. See rule LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code for more information. Noncompliant Code Example (String Literal) From f240c7f9754cc0ebc47e5004f92dbee1f9f4efb4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 16:52:34 +0800 Subject: [PATCH 296/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index cfa116a..197014e 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -68,9 +68,12 @@ public void doSomething() { Java API对java.lang.String类的inern()方法解释如下: ->When the intern() method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. +> 当调用`intern()`方法时,如果常量池中存在这个字符串对象,则会返回这个字符串对象,否则创建这个这个字符串对象,放置常量池并返回。 + +因此,`new String("lock").intern()`返回的对象有可能是JVM中共享的。即使这个字符串对象已经用`private`和`final`修饰,其他的线程仍然可以从JVM的常量池中共享这个对象。使用字符串常量也同样会有这个问题。 + + -Consequently, an interned String object behaves like a global variable in the JVM. As demonstrated in this noncompliant code example, even when every instance of an object maintains its own lock field, the fields all refer to a common String constant. Locking on String constants has the same reuse problem as locking on Boolean constants. Additionally, hostile code from any other package can exploit this vulnerability, if the class is accessible. See rule LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code for more information. Noncompliant Code Example (String Literal) This noncompliant code example locks on a final String literal. From 9a11143dd90d5144db654879dfcd291e6e466d91 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 17:00:24 +0800 Subject: [PATCH 297/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 47 +++++++++--------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 197014e..a0bbf6a 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -72,9 +72,11 @@ Java API对java.lang.String类的inern()方法解释如下: 因此,`new String("lock").intern()`返回的对象有可能是JVM中共享的。即使这个字符串对象已经用`private`和`final`修饰,其他的线程仍然可以从JVM的常量池中共享这个对象。使用字符串常量也同样会有这个问题。 - +除此,恶意代码可能会利用这个漏洞进行攻击。详见:https://www.securecoding.cert.org/confluence/display/java/LCK00-J.+Use+private+final+lock+objects+to+synchronize+classes+that+may+interact+with+untrusted+code Additionally, hostile code from any other package can exploit this vulnerability, if the class is accessible. See rule LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code for more information. + + Noncompliant Code Example (String Literal) This noncompliant code example locks on a final String literal. // This bug was found in jetty-6.1.3 BoundedThreadPool @@ -88,6 +90,8 @@ public void doSomething() { String literals are constant and are automatically interned. Consequently, this example suffers from the same pitfalls as the preceding noncompliant code example. Compliant Solution (String Instance) This compliant solution locks on a noninterned String instance. + +```Java private final String lock = new String("LOCK"); public void doSomething() { @@ -95,9 +99,13 @@ public void doSomething() { // ... } } +``` + A String instance differs from a String literal. The instance has a unique reference and its own intrinsic lock that is distinct from other String object instances or literals. Nevertheless, a better approach is to synchronize on a private final lock object, as shown in the following compliant solution. Compliant Solution (Private Final Lock Object) This compliant solution synchronizes on a private final lock object. This is one of the few cases in which a java.lang.Object instance is useful. + +```Java private final Object lock = new Object(); public void doSomething() { @@ -105,44 +113,15 @@ public void doSomething() { // ... } } +``` + For more information on using an Object as a lock, see rule LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code. Risk Assessment A significant number of concurrency vulnerabilities arise from locking on the wrong kind of object. It is important to consider the properties of the lock object rather than simply scavenging for objects on which to synchronize. -Rule -Severity -Likelihood -Remediation Cost -Priority -Level -LCK01-J -medium -probable -medium -P8 -L2 -Automated Detection -Some static analysis tools can detect violations of this rule. -Tool -Version -Checker -Description -ThreadSafe 1.3 -CCE_CC_REUSEDOBJ_SYNC -Implemented -Bibliography -[API 2006] -Class String, Collections -[Findbugs 2008] - -[Miller 2009] -Locking -[Pugh 2008] -Synchronization -[Tutorials 2008] -Wrapper Implementations - ---------- +##另一个主题 + \ No newline at end of file From f194b678c7ae6305debcb922474615b19e1e8d56 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 17:02:21 +0800 Subject: [PATCH 298/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index a0bbf6a..f22195d 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -74,11 +74,12 @@ Java API对java.lang.String类的inern()方法解释如下: 除此,恶意代码可能会利用这个漏洞进行攻击。详见:https://www.securecoding.cert.org/confluence/display/java/LCK00-J.+Use+private+final+lock+objects+to+synchronize+classes+that+may+interact+with+untrusted+code -Additionally, hostile code from any other package can exploit this vulnerability, if the class is accessible. See rule LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code for more information. +####不合规的代码(字符串字面量) -Noncompliant Code Example (String Literal) This noncompliant code example locks on a final String literal. + +```Java // This bug was found in jetty-6.1.3 BoundedThreadPool private final String lock = "LOCK"; @@ -87,6 +88,8 @@ public void doSomething() { // ... } } +``` + String literals are constant and are automatically interned. Consequently, this example suffers from the same pitfalls as the preceding noncompliant code example. Compliant Solution (String Instance) This compliant solution locks on a noninterned String instance. From 34cbca6c4fdb01f29054a52961eac51e34cd944b Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 17:04:29 +0800 Subject: [PATCH 299/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index f22195d..3f60b41 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -77,11 +77,11 @@ Java API对java.lang.String类的inern()方法解释如下: ####不合规的代码(字符串字面量) -This noncompliant code example locks on a final String literal. +下面不合规代码在字符串的字面量上加锁: ```Java // This bug was found in jetty-6.1.3 BoundedThreadPool -private final String lock = "LOCK"; +private final String lock = "lock"; public void doSomething() { synchronized (lock) { From 5081d2292f3cb0dca3856fae44bc7e26bd027eac Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 17:08:11 +0800 Subject: [PATCH 300/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 3f60b41..064bebd 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -90,8 +90,10 @@ public void doSomething() { } ``` -String literals are constant and are automatically interned. Consequently, this example suffers from the same pitfalls as the preceding noncompliant code example. -Compliant Solution (String Instance) +String字面量实际上是个常量,在内部会调用`intern()`方法。因此,这段代码会陷入上面所说的陷阱: + +####解决方法(String实例) + This compliant solution locks on a noninterned String instance. ```Java From 3a1c2dec69cc62f52b413c5f5f827846dc78296b Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 17:12:46 +0800 Subject: [PATCH 301/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 4 ++++ 1 file changed, 4 insertions(+) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 064bebd..195d0a9 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -106,6 +106,10 @@ public void doSomething() { } ``` +String实例不同于String字面量。String实例拥有各自独立的引用,并不会使用常量池中存在的String实例,因此拥有自己独立的锁。然而,这不是最好的解决方法。最好的解决方法是下面一个。 + +####解决方法(private final Obejct = new Object()) + A String instance differs from a String literal. The instance has a unique reference and its own intrinsic lock that is distinct from other String object instances or literals. Nevertheless, a better approach is to synchronize on a private final lock object, as shown in the following compliant solution. Compliant Solution (Private Final Lock Object) This compliant solution synchronizes on a private final lock object. This is one of the few cases in which a java.lang.Object instance is useful. From 3cb2e732ad96daa2044380b60d9eab3013c1e9b3 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 17:14:04 +0800 Subject: [PATCH 302/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 195d0a9..233d2fe 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -110,9 +110,7 @@ String实例不同于String字面量。String实例拥有各自独立的引用 ####解决方法(private final Obejct = new Object()) -A String instance differs from a String literal. The instance has a unique reference and its own intrinsic lock that is distinct from other String object instances or literals. Nevertheless, a better approach is to synchronize on a private final lock object, as shown in the following compliant solution. -Compliant Solution (Private Final Lock Object) -This compliant solution synchronizes on a private final lock object. This is one of the few cases in which a java.lang.Object instance is useful. +使用Object对象,能够轻松解决上面的问题: ```Java private final Object lock = new Object(); @@ -124,6 +122,8 @@ public void doSomething() { } ``` + + For more information on using an Object as a lock, see rule LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code. Risk Assessment A significant number of concurrency vulnerabilities arise from locking on the wrong kind of object. It is important to consider the properties of the lock object rather than simply scavenging for objects on which to synchronize. From 7a4eabe1cbd028961f154c1717f015d2488a50a4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 17:18:11 +0800 Subject: [PATCH 303/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 233d2fe..3d62aeb 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -122,10 +122,11 @@ public void doSomething() { } ``` +更多的详细信息,请看这里:https://www.securecoding.cert.org/confluence/display/java/LCK00-J.+Use+private+final+lock+objects+to+synchronize+classes+that+may+interact+with+untrusted+code +在私有的不可变Object对象上加锁,可以轻松解决上面遇到的问题。 -For more information on using an Object as a lock, see rule LCK00-J. Use private final lock objects to synchronize classes that may interact with untrusted code. -Risk Assessment +####风险评估(Risk Assessment) A significant number of concurrency vulnerabilities arise from locking on the wrong kind of object. It is important to consider the properties of the lock object rather than simply scavenging for objects on which to synchronize. ---------- From edb0a940ec0f963ff27829f2cc444a3724bc34d9 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 17:19:48 +0800 Subject: [PATCH 304/524] Published with https://stackedit.io/ --- "Java-Security/01.\351\224\201.md" | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git "a/Java-Security/01.\351\224\201.md" "b/Java-Security/01.\351\224\201.md" index 3d62aeb..0b798e3 100644 --- "a/Java-Security/01.\351\224\201.md" +++ "b/Java-Security/01.\351\224\201.md" @@ -19,7 +19,7 @@ public void doSomething() { Boolean类型对象并不适合加锁,因为它只有两个值:`true`和`false`。在JVM中,Boolean类型的两个字面量值都分别都指向同一个共享对象。在这里例子中,lock指向JVM中的一个Boolean.FALSE实例,而这个实例的所有线程共享的。如果有其他的线程不注意地也使用了Boolean.FALSE进行加锁,就可能导致死锁或不可预测的行为。 -####不合规的代码示例(Integer的自动装箱) +####有缺陷的代码示例(Integer的自动装箱) 这个例子中的不合规代码在自动装箱的Integer类型上加锁: @@ -53,7 +53,7 @@ public void doSomething() { ``` 当使用构造方法时,会创建独立的Integer对象,而不会使用常量池中共享的Intege对象。这是一个可接受的解决方法,但这会导致维护问题,开发人员会错误地认为使用自动装箱的Integer也是可以的。更好的解决方法就是`new Object()`对象,最后一个例子会详细介绍。 -####不合规的代码示例(new String("lock").intern()) +####有缺陷的代码示例(new String("lock").intern()) 下面是一个不合规的代码示例: @@ -75,7 +75,7 @@ Java API对java.lang.String类的inern()方法解释如下: 除此,恶意代码可能会利用这个漏洞进行攻击。详见:https://www.securecoding.cert.org/confluence/display/java/LCK00-J.+Use+private+final+lock+objects+to+synchronize+classes+that+may+interact+with+untrusted+code -####不合规的代码(字符串字面量) +####有缺陷的代码(字符串字面量) 下面不合规代码在字符串的字面量上加锁: @@ -127,6 +127,7 @@ public void doSomething() { 在私有的不可变Object对象上加锁,可以轻松解决上面遇到的问题。 ####风险评估(Risk Assessment) + A significant number of concurrency vulnerabilities arise from locking on the wrong kind of object. It is important to consider the properties of the lock object rather than simply scavenging for objects on which to synchronize. ---------- From 8b401b03c9313ea42bf082cb857c86702eba6cad Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 17:22:41 +0800 Subject: [PATCH 305/524] Published with https://stackedit.io/ From 73144e6e98ba3d2bf2658666816f57893b33218e Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Fri, 19 Sep 2014 17:25:13 +0800 Subject: [PATCH 306/524] Published with https://stackedit.io/ From 0fda86d53cbfb7c9d35cb9f5591d968b94e0977d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 20 Sep 2014 00:02:54 +0800 Subject: [PATCH 307/524] Create README.md --- Java-Security/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Java-Security/README.md diff --git a/Java-Security/README.md b/Java-Security/README.md new file mode 100644 index 0000000..e7fe136 --- /dev/null +++ b/Java-Security/README.md @@ -0,0 +1,2 @@ + +翻译自:https://www.securecoding.cert.org/confluence/display/java/The+CERT+Oracle+Secure+Coding+Standard+for+Java From 162963d3668e0565a7823c3d8a211a441330c95a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 20 Sep 2014 00:37:54 +0800 Subject: [PATCH 308/524] Published with https://stackedit.io/ --- ...04\350\257\273\345\206\231\351\224\201.md" | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 5c56693..4f74162 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -19,6 +19,7 @@ A thread that wants write access to the resource can be granted so when no threa With these simple rules in mind we can implement a ReadWriteLock as shown below: +```Java public class ReadWriteLock{ private int readers = 0; @@ -52,6 +53,8 @@ public class ReadWriteLock{ notifyAll(); } } +``` + The ReadWriteLock has two lock methods and two unlock methods. One lock and unlock method for read access and one lock and unlock for write access. The rules for read access are implemented in the lockRead() method. All threads get read access unless there is a thread with write access, or one or more threads have requested write access. @@ -77,13 +80,14 @@ In this situation the previous ReadWriteLock would lock up - a situation similar To make the ReadWriteLock reentrant it is necessary to make a few changes. Reentrance for readers and writers will be dealt with separately. -Read Reentrance +##Read Reentrance To make the ReadWriteLock reentrant for readers we will first establish the rules for read reentrance: A thread is granted read reentrance if it can get read access (no writers or write requests), or if it already has read access (regardless of write requests). To determine if a thread has read access already a reference to each thread granted read access is kept in a Map along with how many times it has acquired read lock. When determing if read access can be granted this Map will be checked for a reference to the calling thread. Here is how the lockRead() and unlockRead() methods looks after that change: +```Java public class ReadWriteLock{ private Map readingThreads = @@ -130,12 +134,15 @@ public class ReadWriteLock{ } } +``` + As you can see read reentrance is only granted if no threads are currently writing to the resource. Additionally, if the calling thread already has read access this takes precedence over any writeRequests. ##Write Reentrance Write reentrance is granted only if the thread has already write access. Here is how the lockWrite() and unlockWrite() methods look after that change: +```Java public class ReadWriteLock{ private Map readingThreads = @@ -179,12 +186,15 @@ public class ReadWriteLock{ return writingThread == callingThread; } } +``` + Notice how the thread currently holding the write lock is now taken into account when determining if the calling thread can get write access. ##Read to Write Reentrance Sometimes it is necessary for a thread that have read access to also obtain write access. For this to be allowed the thread must be the only reader. To achieve this the writeLock() method should be changed a bit. Here is what it would look like: +```Java public class ReadWriteLock{ private Map readingThreads = @@ -234,12 +244,15 @@ public class ReadWriteLock{ } } +``` + Now the ReadWriteLock class is read-to-write access reentrant. -Write to Read Reentrance +##Write to Read Reentrance Sometimes a thread that has write access needs read access too. A writer should always be granted read access if requested. If a thread has write access no other threads can have read nor write access, so it is not dangerous. Here is how the canGrantReadAccess() method will look with that change: +```Java public class ReadWriteLock{ private boolean canGrantReadAccess(Thread callingThread){ @@ -251,11 +264,13 @@ public class ReadWriteLock{ } } +```` ##Fully Reentrant ReadWriteLock Below is the fully reentran ReadWriteLock implementation. I have made a few refactorings to the access conditions to make them easier to read, and thereby easier to convince yourself that they are correct. +```Java public class ReadWriteLock{ private Map readingThreads = @@ -362,15 +377,19 @@ public class ReadWriteLock{ } } +``` ##Calling unlock() From a finally-clause When guarding a critical section with a ReadWriteLock, and the critical section may throw exceptions, it is important to call the readUnlock() and writeUnlock() methods from inside a finally-clause. Doing so makes sure that the ReadWriteLock is unlocked so other threads can lock it. Here is an example: +```Java lock.lockWrite(); try{ //do critical section code, which may throw exception } finally { lock.unlockWrite(); } +``` + This little construct makes sure that the ReadWriteLock is unlocked in case an exception is thrown from the code in the critical section. If unlockWrite() was not called from inside a finally-clause, and an exception was thrown from the critical section, the ReadWriteLock would remain write locked forever, causing all threads calling lockRead() or lockWrite() on that ReadWriteLock instance to halt indefinately. The only thing that could unlock the ReadWriteLockagain would be if the ReadWriteLock is reentrant, and the thread that had it locked when the exception was thrown, later succeeds in locking it, executing the critical section and calling unlockWrite() again afterwards. That would unlock the ReadWriteLock again. But why wait for that to happen, if it happens? Calling unlockWrite() from a finally-clause is a much more robust solution. From 43a2e6a6868282cec8f621adb08ecb221d4d2123 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 20 Sep 2014 00:48:15 +0800 Subject: [PATCH 309/524] Published with https://stackedit.io/ --- ...70\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 4f74162..08662ed 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -6,13 +6,15 @@ Java 5的`java.util.concurrent`包含了读写锁。即使如此,了解读写 ##Java中读/写锁的实现(Read / Write Lock Java Implementation) -首先,我们对写操作和读操作做一个概述: +首先,我们对**读访问**和**写访问**做一个概述: ``` Read Access If no threads are writing, and no threads have requested write access. Write Access If no threads are reading or writing. ``` +如果一个线程请求对资源进行读操作,如果没有线程对资源进行写操作和没有线程请求对资源进行写 + If a thread wants to read the resource, it is okay as long as no threads are writing to it, and no threads have requested write access to the resource. By up-prioritizing write-access requests we assume that write requests are more important than read-requests. Besides, if reads are what happens most often, and we did not up-prioritize writes, starvation could occur. Threads requesting write access would be blocked until all readers had unlocked the ReadWriteLock. If new threads were constantly granted read access the thread waiting for write access would remain blocked indefinately, resulting in starvation. Therefore a thread can only be granted read access if no thread has currently locked the ReadWriteLock for writing, or requested it locked for writing. A thread that wants write access to the resource can be granted so when no threads are reading nor writing to the resource. It doesn't matter how many threads have requested write access or in what sequence, unless you want to guarantee fairness between threads requesting write access. From 1638d5aa47c16ff393913331f6f93a2c3e1a02a4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 20 Sep 2014 01:33:04 +0800 Subject: [PATCH 310/524] Published with https://stackedit.io/ --- ...\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 08662ed..bc44696 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -13,7 +13,7 @@ Read Access If no threads are writing, and no threads have requested write ac Write Access If no threads are reading or writing. ``` -如果一个线程请求对资源进行读操作,如果没有线程对资源进行写操作和没有线程请求对资源进行写 +一个线程请求对资源进行读操作,如果此时没有线程对资源进行写操作和没有线程请求对资源进行写访问,则这个线程可以正常对资源进行读操作。我们假定写访问比读访问更加重要,因此具有更高的优先级。另外,如果写访问更加频繁,而如果我们不降低写访问的优先级,饥饿就会发生。请求写访问的线程会一直阻塞,直到所有的读访问的线程持有的读写锁被释放。如果新的读访问线程总是能够获得锁,写访问的线程就会陷入阻塞,从而造成饥饿。因此, If a thread wants to read the resource, it is okay as long as no threads are writing to it, and no threads have requested write access to the resource. By up-prioritizing write-access requests we assume that write requests are more important than read-requests. Besides, if reads are what happens most often, and we did not up-prioritize writes, starvation could occur. Threads requesting write access would be blocked until all readers had unlocked the ReadWriteLock. If new threads were constantly granted read access the thread waiting for write access would remain blocked indefinately, resulting in starvation. Therefore a thread can only be granted read access if no thread has currently locked the ReadWriteLock for writing, or requested it locked for writing. From ea613a7f8bd069e598766ab776866f84a245c656 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 20 Sep 2014 01:47:10 +0800 Subject: [PATCH 311/524] Published with https://stackedit.io/ --- ...\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index bc44696..fc15233 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -13,7 +13,7 @@ Read Access If no threads are writing, and no threads have requested write ac Write Access If no threads are reading or writing. ``` -一个线程请求对资源进行读操作,如果此时没有线程对资源进行写操作和没有线程请求对资源进行写访问,则这个线程可以正常对资源进行读操作。我们假定写访问比读访问更加重要,因此具有更高的优先级。另外,如果写访问更加频繁,而如果我们不降低写访问的优先级,饥饿就会发生。请求写访问的线程会一直阻塞,直到所有的读访问的线程持有的读写锁被释放。如果新的读访问线程总是能够获得锁,写访问的线程就会陷入阻塞,从而造成饥饿。因此, +一个线程请求对资源进行读操作,如果此时没有线程对资源进行写操作和没有线程请求对资源进行写访问,则这个线程可以正常对资源进行读操作。我们假定写访问比读访问更加重要,因此具有更高的优先级。另外,如果读访问更加频繁,而如果我们不降低写访问的优先级,饥饿就会发生。请求写访问的线程会一直阻塞,直到所有的读访问的线程持有的读写锁被释放。如果新的读访问线程总是能够获得锁,写访问的线程就会陷入阻塞,从而造成饥饿。因此,只有当没有线程正在对共享对象进行写访问并且没有线程请求对共享对象进行写访问,读访问线程才能够获得共享对象的锁。 If a thread wants to read the resource, it is okay as long as no threads are writing to it, and no threads have requested write access to the resource. By up-prioritizing write-access requests we assume that write requests are more important than read-requests. Besides, if reads are what happens most often, and we did not up-prioritize writes, starvation could occur. Threads requesting write access would be blocked until all readers had unlocked the ReadWriteLock. If new threads were constantly granted read access the thread waiting for write access would remain blocked indefinately, resulting in starvation. Therefore a thread can only be granted read access if no thread has currently locked the ReadWriteLock for writing, or requested it locked for writing. From 694f6c09aefd0737de6ce7bc45a01fd1eb67243e Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 20 Sep 2014 01:54:28 +0800 Subject: [PATCH 312/524] Published with https://stackedit.io/ --- ...\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index fc15233..e371d04 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -15,6 +15,8 @@ Write Access If no threads are reading or writing. 一个线程请求对资源进行读操作,如果此时没有线程对资源进行写操作和没有线程请求对资源进行写访问,则这个线程可以正常对资源进行读操作。我们假定写访问比读访问更加重要,因此具有更高的优先级。另外,如果读访问更加频繁,而如果我们不降低写访问的优先级,饥饿就会发生。请求写访问的线程会一直阻塞,直到所有的读访问的线程持有的读写锁被释放。如果新的读访问线程总是能够获得锁,写访问的线程就会陷入阻塞,从而造成饥饿。因此,只有当没有线程正在对共享对象进行写访问并且没有线程请求对共享对象进行写访问,读访问线程才能够获得共享对象的锁。 +当一个线程需要对资源写访问时,如果没有其他线程正在进行读操作或写操作,则这个线程可以获得授权。不管当前有多少线程请求对资源进行写访问以及它们的顺序如何,除非你想实现对写访问请求的公平锁实现。 + If a thread wants to read the resource, it is okay as long as no threads are writing to it, and no threads have requested write access to the resource. By up-prioritizing write-access requests we assume that write requests are more important than read-requests. Besides, if reads are what happens most often, and we did not up-prioritize writes, starvation could occur. Threads requesting write access would be blocked until all readers had unlocked the ReadWriteLock. If new threads were constantly granted read access the thread waiting for write access would remain blocked indefinately, resulting in starvation. Therefore a thread can only be granted read access if no thread has currently locked the ReadWriteLock for writing, or requested it locked for writing. A thread that wants write access to the resource can be granted so when no threads are reading nor writing to the resource. It doesn't matter how many threads have requested write access or in what sequence, unless you want to guarantee fairness between threads requesting write access. From 9031162811e79e13fcd171154e75a8f58082e583 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 20 Sep 2014 01:55:28 +0800 Subject: [PATCH 313/524] Published with https://stackedit.io/ --- ...255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index e371d04..8e9ef27 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -17,15 +17,10 @@ Write Access If no threads are reading or writing. 当一个线程需要对资源写访问时,如果没有其他线程正在进行读操作或写操作,则这个线程可以获得授权。不管当前有多少线程请求对资源进行写访问以及它们的顺序如何,除非你想实现对写访问请求的公平锁实现。 -If a thread wants to read the resource, it is okay as long as no threads are writing to it, and no threads have requested write access to the resource. By up-prioritizing write-access requests we assume that write requests are more important than read-requests. Besides, if reads are what happens most often, and we did not up-prioritize writes, starvation could occur. Threads requesting write access would be blocked until all readers had unlocked the ReadWriteLock. If new threads were constantly granted read access the thread waiting for write access would remain blocked indefinately, resulting in starvation. Therefore a thread can only be granted read access if no thread has currently locked the ReadWriteLock for writing, or requested it locked for writing. - -A thread that wants write access to the resource can be granted so when no threads are reading nor writing to the resource. It doesn't matter how many threads have requested write access or in what sequence, unless you want to guarantee fairness between threads requesting write access. - -With these simple rules in mind we can implement a ReadWriteLock as shown below: +根据这个简单的需求,我们可以参照下面这样实现ReadWriteLock: ```Java public class ReadWriteLock{ - private int readers = 0; private int writers = 0; private int writeRequests = 0; From 1e945c0a0ce861dae0fa4e51054743e77e63c51d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 20 Sep 2014 02:07:29 +0800 Subject: [PATCH 314/524] Published with https://stackedit.io/ From 133384179569e513756d5dc5248252c746e47517 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 20 Sep 2014 02:13:58 +0800 Subject: [PATCH 315/524] Published with https://stackedit.io/ --- ...\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 8e9ef27..d5da0b0 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -54,6 +54,8 @@ public class ReadWriteLock{ } ``` +这个ReadWriteLock类有两个加锁方法以及两个释放锁方法。一个`lock()`方法和一个`unlock()`方法用于读访问,一个`lock()`方法和一个`unlock()`方法用于写访问。 + The ReadWriteLock has two lock methods and two unlock methods. One lock and unlock method for read access and one lock and unlock for write access. The rules for read access are implemented in the lockRead() method. All threads get read access unless there is a thread with write access, or one or more threads have requested write access. From d68ffa34d5d408df8221a636181cfa7481388ea2 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Sat, 20 Sep 2014 02:18:19 +0800 Subject: [PATCH 316/524] Published with https://stackedit.io/ From 43a97e45ac863e414348e820d39fb80cb89d4ef7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 13:14:37 +0800 Subject: [PATCH 317/524] Delete Java --- Java | 131 ----------------------------------------------------------- 1 file changed, 131 deletions(-) delete mode 100644 Java diff --git a/Java b/Java deleted file mode 100644 index 872a216..0000000 --- a/Java +++ /dev/null @@ -1,131 +0,0 @@ -#13.嵌套管程锁死(Nested Monitor Lockout) - -How Nested Monitor Lockout Occurs - -Nested monitor lockout is a problem similar to deadlock. A nested monitor lockout occurs like this: - -Thread 1 synchronizes on A -Thread 1 synchronizes on B (while synchronized on A) -Thread 1 decides to wait for a signal from another thread before continuing -Thread 1 calls B.wait() thereby releasing the lock on B, but not A. - -Thread 2 needs to lock both A and B (in that sequence) - to send Thread 1 the signal. -Thread 2 cannot lock A, since Thread 1 still holds the lock on A. -Thread 2 remain blocked indefinately waiting for Thread1 - to release the lock on A - -Thread 1 remain blocked indefinately waiting for the signal from - Thread 2, thereby - never releasing the lock on A, that must be released to make - it possible for Thread 2 to send the signal to Thread 1, etc. -This may sound like a pretty theoretical situation, but look at the naive Lock implemenation below: - -//lock implementation with nested monitor lockout problem - -public class Lock{ - protected MonitorObject monitorObject = new MonitorObject(); - protected boolean isLocked = false; - - public void lock() throws InterruptedException{ - synchronized(this){ - while(isLocked){ - synchronized(this.monitorObject){ - this.monitorObject.wait(); - } - } - isLocked = true; - } - } - - public void unlock(){ - synchronized(this){ - this.isLocked = false; - synchronized(this.monitorObject){ - this.monitorObject.notify(); - } - } - } -} -Notice how the lock() method first synchronizes on "this", then synchronizes on the monitorObject member. If isLocked is false there is no problem. The thread does not call monitorObject.wait(). If isLocked is true however, the thread calling lock() is parked waiting in the monitorObject.wait() call. - -The problem with this is, that the call to monitorObject.wait() only releases the synchronization monitor on the monitorObject member, and not the synchronization monitor associated with "this". In other words, the thread that was just parked waiting is still holding the synchronization lock on "this". - -When the thread that locked the Lock in the first place tries to unlock it by calling unlock() it will be blocked trying to enter the synchronized(this) block in the unlock() method. It will remain blocked until the thread waiting in lock() leaves the synchronized(this) block. But the thread waiting in the lock() method will not leave that block until the isLocked is set to false, and a monitorObject.notify() is executed, as it happens in unlock(). - -Put shortly, the thread waiting in lock() needs an unlock() call to execute successfully for it to exit lock() and the synchronized blocks inside it. But, no thread can actually execute unlock() until the thread waiting in lock() leaves the outer synchronized block. - -This result is that any thread calling either lock() or unlock() will become blocked indefinately. This is called a nested monitor lockout. - -A More Realistic Example - -You may claim that you would never implement a lock like the one shown earlier. That you would not call wait() and notify() on an internal monitor object, but rather on the This is probably true. But there are situations in which designs like the one above may arise. For instance, if you were to implement fairness in a Lock. When doing so you want each thread to call wait() on each their own queue object, so that you can notify the threads one at a time. - -Look at this naive implementation of a fair lock: - -//Fair Lock implementation with nested monitor lockout problem - -public class FairLock { - private boolean isLocked = false; - private Thread lockingThread = null; - private List waitingThreads = - new ArrayList (); - - public void lock() throws InterruptedException{ - QueueObject queueObject = new QueueObject(); - - synchronized(this){ - waitingThreads.add(queueObject); - - while(isLocked || waitingThreads.get(0) != queueObject){ - - synchronized(queueObject){ - try{ - queueObject.wait(); - }catch(InterruptedException e){ - waitingThreads.remove(queueObject); - throw e; - } - } - } - waitingThreads.remove(queueObject); - isLocked = true; - lockingThread = Thread.currentThread(); - } - } - - public synchronized void unlock(){ - if(this.lockingThread != Thread.currentThread()){ - throw new IllegalMonitorStateException( - "Calling thread has not locked this lock"); - } - isLocked = false; - lockingThread = null; - if(waitingThreads.size() > 0){ - QueueObject queueObject = waitingThread.get(0); - synchronized(queueObject){ - queueObject.notify(); - } - } - } -} -public class QueueObject {} -At first glance this implementation may look fine, but notice how the lock() method calls queueObject.wait(); from inside two synchronized blocks. One synchronized on "this", and nested inside that, a block synchronized on the queueObject local variable. When a thread calls queueObject.wait()it releases the lock on the QueueObject instance, but not the lock associated with "this". - -Notice too, that the unlock() method is declared synchronized which equals a synchronized(this) block. This means, that if a thread is waiting inside lock() the monitor object associated with "this" will be locked by the waiting thread. All threads calling unlock() will remain blocked indefinately, waiting for the waiting thread to release the lock on "this". But this will never happen, since this only happens if a thread succeeds in sending a signal to the waiting thread, and this can only be sent by executing the unlock() method. - -And so, the FairLock implementation from above could lead to nested monitor lockout. A better implementation of a fair lock is described in the text Starvation and Fairness. - -Nested Monitor Lockout vs. Deadlock - -The result of nested monitor lockout and deadlock are pretty much the same: The threads involved end up blocked forever waiting for each other. - -The two situations are not equal though. As explained in the text on Deadlock a deadlock occurs when two threads obtain locks in different order. Thread 1 locks A, waits for B. Thread 2 has locked B, and now waits for A. As explained in the text on Deadlock Prevention deadlocks can be avoided by always locking the locks in the same order (Lock Ordering). However, a nested monitor lockout occurs exactly by two threads taking the locks in the same order. Thread 1 locks A and B, then releases B and waits for a signal from Thread 2. Thread 2 needs both A and B to send Thread 1 the signal. So, one thread is waiting for a signal, and another for a lock to be released. - -The difference is summed up here: - -In deadlock, two threads are waiting for each other to release locks. - -In nested monitor lockout, Thread 1 is holding a lock A, and waits -for a signal from Thread 2. Thread 2 needs the lock A to send the -signal to Thread 1. From c9aa4e7d52c8da729314e40737db7e6fe4b4854d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 13:18:02 +0800 Subject: [PATCH 318/524] Published with https://stackedit.io/ From 8771de7f960794fa518be4e29062fb1c29c970f0 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 14:09:30 +0800 Subject: [PATCH 319/524] Published with https://stackedit.io/ --- ...47\232\204\350\257\273\345\206\231\351\224\201.md" | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index d5da0b0..7cbc6e2 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -56,7 +56,14 @@ public class ReadWriteLock{ 这个ReadWriteLock类有两个加锁方法以及两个释放锁方法。一个`lock()`方法和一个`unlock()`方法用于读访问,一个`lock()`方法和一个`unlock()`方法用于写访问。 -The ReadWriteLock has two lock methods and two unlock methods. One lock and unlock method for read access and one lock and unlock for write access. +读访问的实现在`lockRead()`方法中。如果当前没有线程持有写访问的锁以及没有线程请求写访问,则线程请求读访问都可以授权。 + +写访问的实现在`lockWrite()`方法中。线程请求写访问,会将`writeRequest`加1,然后检查是否可以获得写访问授权。如果当前没有线程在进行读访问以及没有线程写访问,则可以获得写访问授权。 + + + + +(The ReadWriteLock has two lock methods and two unlock methods. One lock and unlock method for read access and one lock and unlock for write access. The rules for read access are implemented in the lockRead() method. All threads get read access unless there is a thread with write access, or one or more threads have requested write access. @@ -66,7 +73,7 @@ It is worth noting that both unlockRead() and unlockWrite() calls notifyAll() ra Inside the ReadWriteLock there are threads waiting for read access, and threads waiting for write access. If a thread awakened by notify() was a read access thread, it would be put back to waiting because there are threads waiting for write access. However, none of the threads awaiting write access are awakened, so nothing more happens. No threads gain neither read nor write access. By calling noftifyAll() all waiting threads are awakened and check if they can get the desired access. -Calling notifyAll() also has another advantage. If multiple threads are waiting for read access and none for write access, and unlockWrite() is called, all threads waiting for read access are granted read access at once - not one by one. +Calling notifyAll() also has another advantage. If multiple threads are waiting for read access and none for write access, and unlockWrite() is called, all threads waiting for read access are granted read access at once - not one by one.) ##读/写锁的可重入性(Read / Write Lock Reentrance) From 1f808c6cf4319ab130a0ffeb8ccd759c77e2fc0e Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 15:12:38 +0800 Subject: [PATCH 320/524] Published with https://stackedit.io/ --- ...270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 3 +++ 1 file changed, 3 insertions(+) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 7cbc6e2..bbf04bf 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -60,8 +60,11 @@ public class ReadWriteLock{ 写访问的实现在`lockWrite()`方法中。线程请求写访问,会将`writeRequest`加1,然后检查是否可以获得写访问授权。如果当前没有线程在进行读访问以及没有线程写访问,则可以获得写访问授权。 +值得注意的是,`unlockRead()`方法和`unlockWrite()`方法调用的是`notifyAll()`方法而非`notify()`方法。至于原因,考虑下面的场景: +假设当前有多个请求**读访问**和**写访问**的线程,当调用`notify()`方法唤醒的线程是**读访问**线程时因为此时有请求**写访问**的线程,被唤醒的线程会继续进入等待状态。然而,因为没有写访问请求的线程被唤醒,所以程序都会因此停止,线程既不能获得读访问授权,也不能获得写访问授权。而调用`notifyAll()`方法可以唤醒所有等待的线程,并检测它们自身是否可以获得锁。 +调用`notifyAll()`方法还有一个好处就是,假设当前有很多请求**读访问**的线程,当**写访问**的线程调用`unlockWrite()`释放锁后,所有的请求**读访问**都可以同时获得授权,而不是一个接着一个授权。 (The ReadWriteLock has two lock methods and two unlock methods. One lock and unlock method for read access and one lock and unlock for write access. From 65d9d57af2dcbdddb2c1f118add773170c9b61be Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 15:34:06 +0800 Subject: [PATCH 321/524] Published with https://stackedit.io/ --- ...7\232\204\350\257\273\345\206\231\351\224\201.md" | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index bbf04bf..e9bc7d4 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -80,6 +80,18 @@ Calling notifyAll() also has another advantage. If multiple threads are waiting ##读/写锁的可重入性(Read / Write Lock Reentrance) +上面实现的ReadWriteLock类并不具有可重入性。如果持有**写访问**锁的线程再次调用`lockWrite()` 方法,则会陷入阻塞。除此之外,考虑下这种情况: + +``` +线程1 授权读访问 +线程2 请求写访问,因为线程1正在读,所以线程2会进入等待状态 +线程1 再次请求读访问,因为当前已有一个写访问请求,所以线程1会进入等待状态 +``` + +这种情况下,ReadWriteLock会被锁死(lock up)(类似于死锁)。其他的读访问和写访问请求也因此不能再获得授权。 + + + The ReadWriteLock class shown earlier is not reentrant. If a thread that has write access requests it again, it will block because there is already one writer - itself. Furthermore, consider this case: Thread 1 gets read access. From 91490af09d0b70be6ca39c866e0083c5bb28e0ed Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 15:39:24 +0800 Subject: [PATCH 322/524] Published with https://stackedit.io/ --- ...\232\204\350\257\273\345\206\231\351\224\201.md" | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index e9bc7d4..949f557 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -90,18 +90,7 @@ Calling notifyAll() also has another advantage. If multiple threads are waiting 这种情况下,ReadWriteLock会被锁死(lock up)(类似于死锁)。其他的读访问和写访问请求也因此不能再获得授权。 - - -The ReadWriteLock class shown earlier is not reentrant. If a thread that has write access requests it again, it will block because there is already one writer - itself. Furthermore, consider this case: - -Thread 1 gets read access. - -Thread 2 requests write access but is blocked because there is one reader. - -Thread 1 re-requests read access (re-enters the lock), but is blocked because there is a write request -In this situation the previous ReadWriteLock would lock up - a situation similar to deadlock. No threads requesting neither read nor write access would be granted so. - -To make the ReadWriteLock reentrant it is necessary to make a few changes. Reentrance for readers and writers will be dealt with separately. +有必要对`ReadWriteLock`做一些修改让它具有**可重入性**。**读访问**和**写访问**的**可重入性**将分别进行处理。 ##Read Reentrance From ca158f800bc813d2996d79a0a824b456d443b65d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 15:41:25 +0800 Subject: [PATCH 323/524] Published with https://stackedit.io/ --- ...\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 949f557..58e28c2 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -92,7 +92,7 @@ Calling notifyAll() also has another advantage. If multiple threads are waiting 有必要对`ReadWriteLock`做一些修改让它具有**可重入性**。**读访问**和**写访问**的**可重入性**将分别进行处理。 -##Read Reentrance +##读可重入性(Read Reentrance) To make the ReadWriteLock reentrant for readers we will first establish the rules for read reentrance: From 6e00efa01b5dc04322f659cd362fdb1e2c07c4a7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 15:44:38 +0800 Subject: [PATCH 324/524] Published with https://stackedit.io/ --- ...47\232\204\350\257\273\345\206\231\351\224\201.md" | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 58e28c2..621f171 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -94,6 +94,10 @@ Calling notifyAll() also has another advantage. If multiple threads are waiting ##读可重入性(Read Reentrance) +为了让`ReadWriteLock`类具有**读可重入性**,我们需要建立读可重入的规则: + +> + To make the ReadWriteLock reentrant for readers we will first establish the rules for read reentrance: A thread is granted read reentrance if it can get read access (no writers or write requests), or if it already has read access (regardless of write requests). @@ -101,9 +105,7 @@ To determine if a thread has read access already a reference to each thread gran ```Java public class ReadWriteLock{ - - private Map readingThreads = - new HashMap (); + private Map readingThreads = new HashMap (); private int writers = 0; private int writeRequests = 0; @@ -114,8 +116,7 @@ public class ReadWriteLock{ wait(); } - readingThreads.put(callingThread, - (getAccessCount(callingThread) + 1)); + readingThreads.put(callingThread,(getAccessCount(callingThread) + 1)); } From a9e967d7807105b90b4948004b6a2852604cf113 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 15:45:26 +0800 Subject: [PATCH 325/524] Published with https://stackedit.io/ --- ...\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 621f171..305d788 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -96,7 +96,7 @@ Calling notifyAll() also has another advantage. If multiple threads are waiting 为了让`ReadWriteLock`类具有**读可重入性**,我们需要建立读可重入的规则: -> +> A thread is granted read reentrance if it can get read access (no writers or write requests), or if it already has read access (regardless of write requests). To make the ReadWriteLock reentrant for readers we will first establish the rules for read reentrance: From 547039412038e1e19c19f64e5dc78bbe19339dd3 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 15:46:24 +0800 Subject: [PATCH 326/524] Published with https://stackedit.io/ --- ...270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" | 3 +++ 1 file changed, 3 insertions(+) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index 305d788..b163d30 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -101,6 +101,9 @@ Calling notifyAll() also has another advantage. If multiple threads are waiting To make the ReadWriteLock reentrant for readers we will first establish the rules for read reentrance: A thread is granted read reentrance if it can get read access (no writers or write requests), or if it already has read access (regardless of write requests). + + + To determine if a thread has read access already a reference to each thread granted read access is kept in a Map along with how many times it has acquired read lock. When determing if read access can be granted this Map will be checked for a reference to the calling thread. Here is how the lockRead() and unlockRead() methods looks after that change: ```Java From ef6e5e271f9a4fe79e6c5707a60f14fecbed0be3 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 15:55:38 +0800 Subject: [PATCH 327/524] Published with https://stackedit.io/ --- ...5\347\232\204\350\257\273\345\206\231\351\224\201.md" | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" index b163d30..8fea652 100644 --- "a/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" +++ "b/Java-Concurrency/17.Java\344\270\255\347\232\204\350\257\273\345\206\231\351\224\201.md" @@ -154,7 +154,7 @@ public class ReadWriteLock{ As you can see read reentrance is only granted if no threads are currently writing to the resource. Additionally, if the calling thread already has read access this takes precedence over any writeRequests. -##Write Reentrance +##写可重入性(Write Reentrance) Write reentrance is granted only if the thread has already write access. Here is how the lockWrite() and unlockWrite() methods look after that change: @@ -206,7 +206,7 @@ public class ReadWriteLock{ Notice how the thread currently holding the write lock is now taken into account when determining if the calling thread can get write access. -##Read to Write Reentrance +##读到写的可重入性(Read to Write Reentrance) Sometimes it is necessary for a thread that have read access to also obtain write access. For this to be allowed the thread must be the only reader. To achieve this the writeLock() method should be changed a bit. Here is what it would look like: @@ -264,7 +264,7 @@ public class ReadWriteLock{ Now the ReadWriteLock class is read-to-write access reentrant. -##Write to Read Reentrance +##写到读的可重入性(Write to Read Reentrance) Sometimes a thread that has write access needs read access too. A writer should always be granted read access if requested. If a thread has write access no other threads can have read nor write access, so it is not dangerous. Here is how the canGrantReadAccess() method will look with that change: @@ -289,8 +289,7 @@ Below is the fully reentran ReadWriteLock implementation. I have made a few refa ```Java public class ReadWriteLock{ - private Map readingThreads = - new HashMap (); + private Map readingThreads = new HashMap (); private int writeAccesses = 0; private int writeRequests = 0; From 4aeff8b5bc8ba9633cc0606c88f7c853c0238ecb Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 15:58:24 +0800 Subject: [PATCH 328/524] Published with https://stackedit.io/ From 36208ceb3afc7fb46c160b9a33ac4fb58ee23682 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 16:04:32 +0800 Subject: [PATCH 329/524] Published with https://stackedit.io/ --- ...9.\344\277\241\345\217\267\351\207\217.md" | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index 706ac5a..67ff97a 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -1,13 +1,21 @@ #19.信号量 + + A Semaphore is a thread synchronization construct that can be used either to send signals between threads to avoid missed signals, or to guard a critical section like you would with a lock. Java 5 comes with semaphore implementations in the java.util.concurrent package so you don't have to implement your own semaphores. Still, it can be useful to know the theory behind their implementation and use. Java 5 comes with a built-in Semaphore so you don't have to implement your own. You can read more about it in the java.util.concurrent.Semaphore text, in my java.util.concurrent tutorial. -##Simple Semaphore +一个信号是可以使用,也可以在线程之间发送信号,以避免错过的信号,或守卫的关键部分,就像您有锁的线程同步结构。 Java 5中自带的java.util.concurrent包信号量的实现,所以你不必实现自己的信号量。不过,这可能是有用的,以知道它们的实施和使用背后的理论。 + +Java 5中带有一个内置的信号量,这样你就不必实现自己。你可以阅读更多关于它的java.util.concurrent.Semaphore中的文字,在我的java.util.concurrent教程。 + + +##简单的信号量实现(Simple Semaphore) Here is a simple Semaphore implementation: +```Java public class Semaphore { private boolean signal = false; @@ -22,6 +30,8 @@ public class Semaphore { } } +``` + The take() method sends a signal which is stored internally in the Semaphore. The release() method waits for a signal. When received the signal flag is cleared again, and the release() method exited. Using a semaphore like this you can avoid missed signals. You will call take() instead of notify() and release() instead of wait(). If the call to take() happens before the call to release() the thread calling release() will still know that take() was called, because the signal is stored internally in the signal variable. This is not the case with wait() and notify(). @@ -32,6 +42,7 @@ The names take() and release() may seem a bit odd when using a semaphore for sig Here is a simplified example of two threads signaling each other using a Semaphore: +```Java Semaphore semaphore = new Semaphore(); SendingThread sender = new SendingThread(semaphore); @@ -69,11 +80,14 @@ public class RecevingThread { } } } +``` + ##Counting Semaphore The Semaphore implementation in the previous section does not count the number of signals sent to it by take() method calls. We can change the Semaphore to do so. This is called a counting semaphore. Here is a simple implementation of a counting semaphore: +```Java public class CountingSemaphore { private int signals = 0; @@ -88,11 +102,14 @@ public class CountingSemaphore { } } +``` + ##Bounded Semaphore The CoutingSemaphore has no upper bound on how many signals it can store. We can change the semaphore implementation to have an upper bound, like this: +```Java public class BoundedSemaphore { private int signals = 0; private int bound = 0; @@ -113,12 +130,15 @@ public class BoundedSemaphore { this.notify(); } } +``` + Notice how the take() method now blocks if the number of signals is equal to the upper bound. Not until a thread has called release() will the thread calling take() be allowed to deliver its signal, if the BoundedSemaphore has reached its upper signal limit. -Using Semaphores as Locks +##Using Semaphores as Locks It is possible to use a bounded semaphore as a lock. To do so, set the upper bound to 1, and have the call to take() and release() guard the critical section. Here is an example: +```Java BoundedSemaphore semaphore = new BoundedSemaphore(1); ... @@ -130,6 +150,8 @@ try{ } finally { semaphore.release(); } +``` + In contrast to the signaling use case the methods take() and release() are now called by the same thread. Since only one thread is allowed to take the semaphore, all other threads calling take() will be blocked until release() is called. The call to release() will never block since there has always been a call to take() first. You can also use a bounded semaphore to limit the number of threads allowed into a section of code. For instance, in the example above, what would happen if you set the limit of the BoundedSemaphore to 5? 5 threads would be allowed to enter the critical section at a time. You would have to make sure though, that the thread operations do not conflict for these 5 threads, or you application will fail. From 52bc9fccb268e6d8907603bca007ef97cc51ca32 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 16:13:12 +0800 Subject: [PATCH 330/524] Published with https://stackedit.io/ --- .../19.\344\277\241\345\217\267\351\207\217.md" | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index 67ff97a..b68b247 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -1,16 +1,13 @@ #19.信号量 +信号量是一种线程同步结构,它可以用于线程间的信号通信,以及可以像锁一样来保护临界区。Java 5在`java.util.concurrency`包中引入了信号量(Semaphores)的实现。但是,了解信号量背后的实现原来对我们也是非常有帮助的。 +Java 5引入了信号量的实现,因此,你不必自己去实现信号量。详细的介绍请看这里:http://tutorials.jenkov.com/java-util-concurrent/semaphore.html A Semaphore is a thread synchronization construct that can be used either to send signals between threads to avoid missed signals, or to guard a critical section like you would with a lock. Java 5 comes with semaphore implementations in the java.util.concurrent package so you don't have to implement your own semaphores. Still, it can be useful to know the theory behind their implementation and use. Java 5 comes with a built-in Semaphore so you don't have to implement your own. You can read more about it in the java.util.concurrent.Semaphore text, in my java.util.concurrent tutorial. -一个信号是可以使用,也可以在线程之间发送信号,以避免错过的信号,或守卫的关键部分,就像您有锁的线程同步结构。 Java 5中自带的java.util.concurrent包信号量的实现,所以你不必实现自己的信号量。不过,这可能是有用的,以知道它们的实施和使用背后的理论。 - -Java 5中带有一个内置的信号量,这样你就不必实现自己。你可以阅读更多关于它的java.util.concurrent.Semaphore中的文字,在我的java.util.concurrent教程。 - - ##简单的信号量实现(Simple Semaphore) Here is a simple Semaphore implementation: From 23ed9adcec28fe55e5e8e858c2c83cabdf1f6eb4 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 16:13:36 +0800 Subject: [PATCH 331/524] Published with https://stackedit.io/ --- "Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index b68b247..c890efd 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -10,7 +10,7 @@ Java 5 comes with a built-in Semaphore so you don't have to implement your own. ##简单的信号量实现(Simple Semaphore) -Here is a simple Semaphore implementation: +下面是一个简单的信号量类的实现: ```Java public class Semaphore { From 43a59aa55d2175db41cef12d11de7541f43f4da6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 16:57:42 +0800 Subject: [PATCH 332/524] Published with https://stackedit.io/ --- "Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index c890efd..930ec1e 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -22,7 +22,9 @@ public class Semaphore { } public synchronized void release() throws InterruptedException{ - while(!this.signal) wait(); + while(!this.signal) { + wait(); + } this.signal = false; } From d3c59f6e93f27795dbd049087e567a47632250de Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 17:06:06 +0800 Subject: [PATCH 333/524] Published with https://stackedit.io/ --- .../19.\344\277\241\345\217\267\351\207\217.md" | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index 930ec1e..460f9b4 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -1,13 +1,9 @@ #19.信号量 -信号量是一种线程同步结构,它可以用于线程间的信号通信,以及可以像锁一样来保护临界区。Java 5在`java.util.concurrency`包中引入了信号量(Semaphores)的实现。但是,了解信号量背后的实现原来对我们也是非常有帮助的。 +信号量是一种线程同步结构,它可以用于线程间的信号通信,也可以用来像锁一样来保护临界区。Java 5在`java.util.concurrency`包中引入了信号量(Semaphores)的实现。但是,了解信号量背后的实现原来对我们也是非常有帮助的。 Java 5引入了信号量的实现,因此,你不必自己去实现信号量。详细的介绍请看这里:http://tutorials.jenkov.com/java-util-concurrent/semaphore.html -A Semaphore is a thread synchronization construct that can be used either to send signals between threads to avoid missed signals, or to guard a critical section like you would with a lock. Java 5 comes with semaphore implementations in the java.util.concurrent package so you don't have to implement your own semaphores. Still, it can be useful to know the theory behind their implementation and use. - -Java 5 comes with a built-in Semaphore so you don't have to implement your own. You can read more about it in the java.util.concurrent.Semaphore text, in my java.util.concurrent tutorial. - ##简单的信号量实现(Simple Semaphore) 下面是一个简单的信号量类的实现: From e489ccec56170cfe71667ce49686faaeeaa57ea6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 17:21:46 +0800 Subject: [PATCH 334/524] Published with https://stackedit.io/ --- .../19.\344\277\241\345\217\267\351\207\217.md" | 6 ++++++ 1 file changed, 6 insertions(+) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index 460f9b4..cf35307 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -27,6 +27,12 @@ public class Semaphore { } ``` +Semmaphore类的`take()`方法用于发送信号,`release()`方法用于等待信号。 + +使用信号量可以避免信号丢失的问题。在这里,`take()`方法代替了`notify()`方法,`release()`方法代替了`wait()`方法。如果我们在调用`take()`方法之前调用了`release()`方法,`release()`方法通过判断signal变量可以判断`take()`被调用过,因此不会造成信号丢失的问题。而直接`wait()`和`notify()`则会有这个问题。 + +在使用信号量(Semaphore )进行信号通信(Signaling)时,`take()`和`release()`方法的命名似乎有点过时。 + The take() method sends a signal which is stored internally in the Semaphore. The release() method waits for a signal. When received the signal flag is cleared again, and the release() method exited. Using a semaphore like this you can avoid missed signals. You will call take() instead of notify() and release() instead of wait(). If the call to take() happens before the call to release() the thread calling release() will still know that take() was called, because the signal is stored internally in the signal variable. This is not the case with wait() and notify(). From 1640276f641bd30c07fd4bfe112c25145b666370 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 17:30:37 +0800 Subject: [PATCH 335/524] Published with https://stackedit.io/ --- ...9.\344\277\241\345\217\267\351\207\217.md" | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index cf35307..0ed8ece 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -31,27 +31,21 @@ Semmaphore类的`take()`方法用于发送信号,`release()`方法用于等待 使用信号量可以避免信号丢失的问题。在这里,`take()`方法代替了`notify()`方法,`release()`方法代替了`wait()`方法。如果我们在调用`take()`方法之前调用了`release()`方法,`release()`方法通过判断signal变量可以判断`take()`被调用过,因此不会造成信号丢失的问题。而直接`wait()`和`notify()`则会有这个问题。 -在使用信号量(Semaphore )进行信号通信(Signaling)时,`take()`和`release()`方法的命名似乎有点过时。 +在使用信号量(Semaphore )进行信号通信(Signaling)时,`take()`和`release()`方法的命名似乎有点过时。下面的示例中会使用Lock中的方法命名,使得方法命名更加**语义化**( The names origin from the use of semaphores as locks, as explained later in this text. In that case the names make more sense.)。 -The take() method sends a signal which is stored internally in the Semaphore. The release() method waits for a signal. When received the signal flag is cleared again, and the release() method exited. +##使用信号量通信(Using Semaphores for Signaling) -Using a semaphore like this you can avoid missed signals. You will call take() instead of notify() and release() instead of wait(). If the call to take() happens before the call to release() the thread calling release() will still know that take() was called, because the signal is stored internally in the signal variable. This is not the case with wait() and notify(). - -The names take() and release() may seem a bit odd when using a semaphore for signaling. The names origin from the use of semaphores as locks, as explained later in this text. In that case the names make more sense. - -##Using Semaphores for Signaling - -Here is a simplified example of two threads signaling each other using a Semaphore: +下面的示例的两个线程使用信号量进行通信: ```Java Semaphore semaphore = new Semaphore(); SendingThread sender = new SendingThread(semaphore); - ReceivingThread receiver = new ReceivingThread(semaphore); receiver.start(); sender.start(); + public class SendingThread { Semaphore semaphore = null; @@ -67,6 +61,7 @@ public class SendingThread { } } } + public class RecevingThread { Semaphore semaphore = null; @@ -84,7 +79,7 @@ public class RecevingThread { ``` -##Counting Semaphore +##计数信号量(Counting Semaphore) The Semaphore implementation in the previous section does not count the number of signals sent to it by take() method calls. We can change the Semaphore to do so. This is called a counting semaphore. Here is a simple implementation of a counting semaphore: @@ -106,7 +101,7 @@ public class CountingSemaphore { ``` -##Bounded Semaphore +##右界信号量(Bounded Semaphore) The CoutingSemaphore has no upper bound on how many signals it can store. We can change the semaphore implementation to have an upper bound, like this: @@ -135,7 +130,7 @@ public class BoundedSemaphore { Notice how the take() method now blocks if the number of signals is equal to the upper bound. Not until a thread has called release() will the thread calling take() be allowed to deliver its signal, if the BoundedSemaphore has reached its upper signal limit. -##Using Semaphores as Locks +##像锁一样使用信号量(Using Semaphores as Locks) It is possible to use a bounded semaphore as a lock. To do so, set the upper bound to 1, and have the call to take() and release() guard the critical section. Here is an example: From 50252f8229c72215e0af06c3ec39684ddda91856 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 17:38:05 +0800 Subject: [PATCH 336/524] Published with https://stackedit.io/ --- .../19.\344\277\241\345\217\267\351\207\217.md" | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index 0ed8ece..667c807 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -81,7 +81,7 @@ public class RecevingThread { ##计数信号量(Counting Semaphore) -The Semaphore implementation in the previous section does not count the number of signals sent to it by take() method calls. We can change the Semaphore to do so. This is called a counting semaphore. Here is a simple implementation of a counting semaphore: +上面实现的Semaphore类,并没有计算通过调用`take()`方法发送的信号的次数。我们通过修改让它提供这个功能。这个称之为**计数信号量**。下面是一个简单的计数信号量的实现: ```Java public class CountingSemaphore { @@ -93,7 +93,9 @@ public class CountingSemaphore { } public synchronized void release() throws InterruptedException{ - while(this.signals == 0) wait(); + while(this.signals == 0) { + wait(); + } this.signals--; } From 9c9e460c66dcc7ae3d390f974c48e3ea5b7dc06e Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 17:49:02 +0800 Subject: [PATCH 337/524] Published with https://stackedit.io/ --- .../19.\344\277\241\345\217\267\351\207\217.md" | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index 667c807..c52e627 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -103,9 +103,9 @@ public class CountingSemaphore { ``` -##右界信号量(Bounded Semaphore) +##有界信号量(Bounded Semaphore) -The CoutingSemaphore has no upper bound on how many signals it can store. We can change the semaphore implementation to have an upper bound, like this: +CountingSemaphores只是存储了发送的信号量的个数,但是没有限定信号量的个数。我们可以按照下面这个例子让它限制信号量的上界: ```Java public class BoundedSemaphore { @@ -130,6 +130,8 @@ public class BoundedSemaphore { } ``` + + Notice how the take() method now blocks if the number of signals is equal to the upper bound. Not until a thread has called release() will the thread calling take() be allowed to deliver its signal, if the BoundedSemaphore has reached its upper signal limit. ##像锁一样使用信号量(Using Semaphores as Locks) From 5e328f22c951ec021fa26e0ac8b68c5534488649 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 17:54:02 +0800 Subject: [PATCH 338/524] Published with https://stackedit.io/ --- .../19.\344\277\241\345\217\267\351\207\217.md" | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index c52e627..82038cd 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -117,22 +117,24 @@ public class BoundedSemaphore { } public synchronized void take() throws InterruptedException{ - while(this.signals == bound) wait(); + while(this.signals == bound) { + wait(); + } this.signals++; this.notify(); } public synchronized void release() throws InterruptedException{ - while(this.signals == 0) wait(); + while(this.signals == 0) { + wait(); + } this.signals--; this.notify(); } } ``` - - -Notice how the take() method now blocks if the number of signals is equal to the upper bound. Not until a thread has called release() will the thread calling take() be allowed to deliver its signal, if the BoundedSemaphore has reached its upper signal limit. +注意这里的`take()`方法,如果signals的个数达到上限则线程进入阻塞,直到有线程调用`release()`方法,当前线程才能被允许发送信号。 ##像锁一样使用信号量(Using Semaphores as Locks) From 803d6dfde3583a371c79d4345df3424ea7d15269 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 17:57:03 +0800 Subject: [PATCH 339/524] Published with https://stackedit.io/ --- "Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index 82038cd..cb368f0 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -138,13 +138,13 @@ public class BoundedSemaphore { ##像锁一样使用信号量(Using Semaphores as Locks) +我们可以把有**界信号量(bounded semaphore)**当成锁使用。这时候,我们将上界设置为1,用`take()`方法和`release()`方法包裹临界区。如下面这个例子: + It is possible to use a bounded semaphore as a lock. To do so, set the upper bound to 1, and have the call to take() and release() guard the critical section. Here is an example: ```Java BoundedSemaphore semaphore = new BoundedSemaphore(1); -... - semaphore.take(); try{ From dabdaabb109c7995e81134821cb8dfd5b1ff048b Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 18:07:27 +0800 Subject: [PATCH 340/524] Published with https://stackedit.io/ --- "Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index cb368f0..357618e 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -154,7 +154,9 @@ try{ } ``` -In contrast to the signaling use case the methods take() and release() are now called by the same thread. Since only one thread is allowed to take the semaphore, all other threads calling take() will be blocked until release() is called. The call to release() will never block since there has always been a call to take() first. +与发送信号不同,这里的`take()`方法和`release()`方法都是在同一个线程里面调用的。这是因为当上界为1时,一个线程调用`take()`方法后,其他调用`take()`方法的线程都会阻塞,直到这个线程调用`release()`方法。 + +你也可以利用**有界信号量**去限制同时进入同一个临界区的线程数量。举个例子,在上面的例子中,假如将limit的值设置为5会发生什么情况呢?5个线程会被允许同时进入同一个临界区。 You can also use a bounded semaphore to limit the number of threads allowed into a section of code. For instance, in the example above, what would happen if you set the limit of the BoundedSemaphore to 5? 5 threads would be allowed to enter the critical section at a time. You would have to make sure though, that the thread operations do not conflict for these 5 threads, or you application will fail. From 36cee013ea69ee96a4ea83a792da1565a7f3eff6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 18:11:06 +0800 Subject: [PATCH 341/524] Published with https://stackedit.io/ --- .../19.\344\277\241\345\217\267\351\207\217.md" | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" index 357618e..5fdcae9 100644 --- "a/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" +++ "b/Java-Concurrency/19.\344\277\241\345\217\267\351\207\217.md" @@ -156,9 +156,7 @@ try{ 与发送信号不同,这里的`take()`方法和`release()`方法都是在同一个线程里面调用的。这是因为当上界为1时,一个线程调用`take()`方法后,其他调用`take()`方法的线程都会阻塞,直到这个线程调用`release()`方法。 -你也可以利用**有界信号量**去限制同时进入同一个临界区的线程数量。举个例子,在上面的例子中,假如将limit的值设置为5会发生什么情况呢?5个线程会被允许同时进入同一个临界区。 +你也可以利用**有界信号量**去限制同时进入同一个临界区的线程数量。举个例子,在上面的例子中,假如将limit的值设置为5会发生什么情况呢?5个线程会被允许同时进入同一个临界区。当然,你也需要确保这5个线程间的操作不会互相干扰,否则应用程序会因此挂掉。 -You can also use a bounded semaphore to limit the number of threads allowed into a section of code. For instance, in the example above, what would happen if you set the limit of the BoundedSemaphore to 5? 5 threads would be allowed to enter the critical section at a time. You would have to make sure though, that the thread operations do not conflict for these 5 threads, or you application will fail. - -The relase() method is called from inside a finally-block to make sure it is called even if an exception is thrown from the critical section. +`release()`方法在`finally`块中被调用,这样就可以确保即使临界区发生异常时,`release()`总能够被调用。 From 7d49d8a84ad330d64c34d4416831d3490227da9d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 18:22:13 +0800 Subject: [PATCH 342/524] Published with https://stackedit.io/ From 9936de097d2de6c58cdd2a80e85cbfb894b6c176 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 18:35:12 +0800 Subject: [PATCH 343/524] Published with https://stackedit.io/ --- .../20.\351\230\273\345\241\236\351\230\237\345\210\227.md" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" "b/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" index 96bd0dc..4c3b1aa 100644 --- "a/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" +++ "b/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" @@ -1,5 +1,7 @@ #20.阻塞队列 +**阻塞队列**是这样一种队列:当队列为空时**出列(dequeue)**会阻塞,当队列满时**入队**会阻塞。 + A blocking queue is a queue that blocks when you try to dequeue from it and the queue is empty, or if you try to enqueue items to it and the queue is already full. A thread trying to dequeue from an empty queue is blocked until some other thread inserts an item into the queue. A thread trying to enqueue an item in a full queue is blocked until some other thread makes space in the queue, either by dequeuing one or more items or clearing the queue completely. Here is a diagram showing two threads cooperating via a blocking queue: @@ -11,7 +13,7 @@ A BlockingQueue with one thread putting into it, and another thread taking from Java 5 comes with blocking queue implementations in the java.util.concurrent package. You can read about that class in my java.util.concurrent.BlockingQueue tutorial. Even if Java 5 comes with a blocking queue implementation, it can be useful to know the theory behind their implementation. -Blocking Queue Implementation +##Blocking Queue Implementation The implementation of a blocking queue looks similar to a Bounded Semaphore. Here is a simple implementation of a blocking queue: From ab198442f582e8992a3c233297ebe2e48d981a18 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 18:49:40 +0800 Subject: [PATCH 344/524] Published with https://stackedit.io/ --- ...273\345\241\236\351\230\237\345\210\227.md" | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git "a/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" "b/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" index 4c3b1aa..004c00a 100644 --- "a/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" +++ "b/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" @@ -1,22 +1,19 @@ #20.阻塞队列 -**阻塞队列**是这样一种队列:当队列为空时**出列(dequeue)**会阻塞,当队列满时**入队**会阻塞。 +**阻塞队列**是这样一种队列:当队列为空时**出列(dequeue)**会阻塞,当队列满时**入队**会阻塞。当一个线程试图从一个空队列出列就会进入阻塞,直到其他线程将元素入列;当一个线程试图从一个满的队列中入列也会阻塞,直到其他线程将对队列中的元素出列或者将队列清空。 -A blocking queue is a queue that blocks when you try to dequeue from it and the queue is empty, or if you try to enqueue items to it and the queue is already full. A thread trying to dequeue from an empty queue is blocked until some other thread inserts an item into the queue. A thread trying to enqueue an item in a full queue is blocked until some other thread makes space in the queue, either by dequeuing one or more items or clearing the queue completely. +下面的图展示了两个线程如何跟阻塞队列进行交互: -Here is a diagram showing two threads cooperating via a blocking queue: - + -A BlockingQueue with one thread putting into it, and another thread taking from it. -A BlockingQueue with one thread putting into it, and another thread taking from it. -Java 5 comes with blocking queue implementations in the java.util.concurrent package. You can read about that class in my java.util.concurrent.BlockingQueue tutorial. Even if Java 5 comes with a blocking queue implementation, it can be useful to know the theory behind their implementation. +Java 5的`java.util.concurrent`包中引入了阻塞队列的实现。即使如此,了解底层的实现原理也是非常有必要和有帮助的。 +##阻塞队列的实现(Blocking Queue Implementation) -##Blocking Queue Implementation - -The implementation of a blocking queue looks similar to a Bounded Semaphore. Here is a simple implementation of a blocking queue: + **阻塞队列**的实现跟**有界信号量**的实现类似。下面是一个阻塞队列的实现: +```Java public class BlockingQueue { private List queue = new LinkedList(); @@ -52,5 +49,6 @@ public class BlockingQueue { } } +``` Notice how notifyAll() is only called from enqueue() and dequeue() if the queue size is equal to the size bounds (0 or limit). If the queue size is not equal to either bound when enqueue() or dequeue() is called, there can be no threads waiting to either enqueue or dequeue items. \ No newline at end of file From d0740497a3c40f1e3349502db551d9719c2c1d62 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 18:50:34 +0800 Subject: [PATCH 345/524] Published with https://stackedit.io/ --- .../20.\351\230\273\345\241\236\351\230\237\345\210\227.md" | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" "b/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" index 004c00a..a2061b1 100644 --- "a/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" +++ "b/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" @@ -24,8 +24,7 @@ public class BlockingQueue { } - public synchronized void enqueue(Object item) - throws InterruptedException { + public synchronized void enqueue(Object item) throws InterruptedException { while(this.queue.size() == this.limit) { wait(); } @@ -36,8 +35,7 @@ public class BlockingQueue { } - public synchronized Object dequeue() - throws InterruptedException{ + public synchronized Object dequeue() throws InterruptedException{ while(this.queue.size() == 0){ wait(); } From b03a6c9983c5e3e643b1fea8237e13fa1f634fe7 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Mon, 22 Sep 2014 18:54:38 +0800 Subject: [PATCH 346/524] Published with https://stackedit.io/ --- .../20.\351\230\273\345\241\236\351\230\237\345\210\227.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" "b/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" index a2061b1..660a140 100644 --- "a/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" +++ "b/Java-Concurrency/20.\351\230\273\345\241\236\351\230\237\345\210\227.md" @@ -49,4 +49,4 @@ public class BlockingQueue { } ``` -Notice how notifyAll() is only called from enqueue() and dequeue() if the queue size is equal to the size bounds (0 or limit). If the queue size is not equal to either bound when enqueue() or dequeue() is called, there can be no threads waiting to either enqueue or dequeue items. \ No newline at end of file +ok,很简单,也不过多解释了! \ No newline at end of file From eba5e579aa42d746665c809d61d9dc2b16965282 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 00:10:58 +0800 Subject: [PATCH 347/524] Published with https://stackedit.io/ From a5f88c0b662258db15ff094f42cdafb8a6cee3e6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 00:11:31 +0800 Subject: [PATCH 348/524] Published with https://stackedit.io/ --- "Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" | 4 ++++ 1 file changed, 4 insertions(+) diff --git "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" index c457eef..759a402 100644 --- "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" +++ "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" @@ -10,6 +10,7 @@ Java 5 comes with built in thread pools in the java.util.concurrent package, so Here is a simple thread pool implementation: +```Java public class ThreadPool { private BlockingQueue taskQueue = null; @@ -72,6 +73,9 @@ public class PoolThread extends Thread { return isStopped; } } +``` + + The thread pool implementation consists of two parts. A ThreadPool class which is the public interface to the thread pool, and a PoolThread class which implements the threads that execute the tasks. To execute a task the method ThreadPool.execute(Runnable r) is called with a Runnable implementation as parameter. The Runnable is enqueued in the blocking queue internally, waiting to be dequeued. From 4dde4557b0cd2279b9394fc4c6bf06b5bb073204 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 00:45:20 +0800 Subject: [PATCH 349/524] Published with https://stackedit.io/ --- "Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" | 4 ++++ 1 file changed, 4 insertions(+) diff --git "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" index 759a402..4a784da 100644 --- "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" +++ "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" @@ -1,5 +1,9 @@ #21.线程池 +当你需要在应用程序中限制同一时间线程的数量时,线程池就显得非常有用,因为创建并启动新的线程是消耗性能的。 + +给每个任务创建并启动单独的线程不同,你可以将任务交给线程池,当线程中有线程空闲时,x + Thread Pools are useful when you need to limit the number of threads running in your application at the same time. There is a performance overhead associated with starting a new thread, and each thread is also allocated some memory for its stack etc. Instead of starting a new thread for every task to execute concurrently, the task can be passed to a thread pool. As soon as the pool has any idle threads the task is assigned to one of them and executed. Internally the tasks are inserted into a Blocking Queue which the threads in the pool are dequeuing from. When a new task is inserted into the queue one of the idle threads will dequeue it successfully and execute it. The rest of the idle threads in the pool will be blocked waiting to dequeue tasks. From 77f2921ea65b0eeaaa737bdd928386dc504ecc92 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 01:24:10 +0800 Subject: [PATCH 350/524] Published with https://stackedit.io/ --- ...1.\347\272\277\347\250\213\346\261\240.md" | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" index 4a784da..dee496f 100644 --- "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" +++ "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" @@ -2,21 +2,16 @@ 当你需要在应用程序中限制同一时间线程的数量时,线程池就显得非常有用,因为创建并启动新的线程是消耗性能的。 -给每个任务创建并启动单独的线程不同,你可以将任务交给线程池,当线程中有线程空闲时,x +给每个任务创建并启动单独的线程不同,你可以将任务交给线程池,当线程中有线程空闲时,线程池就会将任务非配给线程执行。在线程池内部,任务被插入到一个阻塞队列里面,空闲线程将从这个队列汇总出列(dequeue)需要执行的任务。如果队列中没有任务,线程池中的空闲线程就会进入阻塞等待新的任务。 -Thread Pools are useful when you need to limit the number of threads running in your application at the same time. There is a performance overhead associated with starting a new thread, and each thread is also allocated some memory for its stack etc. +线程池经常被用于多线程处理的服务器中。每个到达服务器的连接都会被包装成一个任务然后交给线程池进行处理,线程池中的线程会并行地对这些任务进行处理。 -Instead of starting a new thread for every task to execute concurrently, the task can be passed to a thread pool. As soon as the pool has any idle threads the task is assigned to one of them and executed. Internally the tasks are inserted into a Blocking Queue which the threads in the pool are dequeuing from. When a new task is inserted into the queue one of the idle threads will dequeue it successfully and execute it. The rest of the idle threads in the pool will be blocked waiting to dequeue tasks. +Java 5中内置了线程池的实现,所以你不必要自己去实现线程池。但是了解其中的实现原理是非常有必要和有帮助的。 -Thread pools are often used in multi threaded servers. Each connection arriving at the server via the network is wrapped as a task and passed on to a thread pool. The threads in the thread pool will process the requests on the connections concurrently. A later trail will get into detail about implementing multithreaded servers in Java. - -Java 5 comes with built in thread pools in the java.util.concurrent package, so you don't have to implement your own thread pool. You can read more about it in my text on the java.util.concurrent.ExecutorService. Still it can be useful to know a bit about the implementation of a thread pool anyways. - -Here is a simple thread pool implementation: +下面是一个线程池的简单实现: ```Java public class ThreadPool { - private BlockingQueue taskQueue = null; private List threads = new ArrayList (); private boolean isStopped = false; @@ -33,9 +28,9 @@ public class ThreadPool { } public void synchronized execute(Runnable task){ - if(this.isStopped) throw - new IllegalStateException("ThreadPool is stopped"); - + if(this.isStopped) { + throw new IllegalStateException("ThreadPool is stopped"); + } this.taskQueue.enqueue(task); } From d20c2e1f044e20fc8cc4348380d5f40a29469fe5 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 01:51:04 +0800 Subject: [PATCH 351/524] Published with https://stackedit.io/ --- ...1.\347\272\277\347\250\213\346\261\240.md" | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" index dee496f..035bad8 100644 --- "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" +++ "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" @@ -40,10 +40,9 @@ public class ThreadPool { thread.stop(); } } - } -public class PoolThread extends Thread { +public class PoolThread extends Thread { private BlockingQueue taskQueue = null; private boolean isStopped = false; @@ -74,13 +73,21 @@ public class PoolThread extends Thread { } ``` +线程池的实现由两部分组成。ThreadPool类是公开的线程池接口,PoolThread类继承Thread用于执行线程。 + +执行任务的`PoolThread.execute(Runnable r)`方法带有一个Runnable作为参数。Runnable对象入列到**阻塞队列**中并等待出列被线程执行。 + +当线程池中有空闲线程时,阻塞队列的Runnable对象就会被出列并被线程执行。你可以看下`PoolThread.run()`方法的实现,当前任务执行完后,会再次检查阻塞队列是否有任务执行,直到`stop()`方法被调用。 + +当需要停止线程池可以调用`ThreadPool.stop()`方法,此时会有一个isStopped成员变量来标记线程池被停止。然后逐个调用线程池中线程的`PoolThread.stop()`方法。注意当线程池被停止后再调用`execute()`方法,则会抛出IllegaStateException异常。 + + -The thread pool implementation consists of two parts. A ThreadPool class which is the public interface to the thread pool, and a PoolThread class which implements the threads that execute the tasks. -To execute a task the method ThreadPool.execute(Runnable r) is called with a Runnable implementation as parameter. The Runnable is enqueued in the blocking queue internally, waiting to be dequeued. +The threads will stop after finishing any task they are currently executing. Notice the this.interrupt() call in PoolThread.stop(). This makes sure that a thread blocked in a wait() call inside the taskQueue.dequeue() call breaks out of the wait() call, and leaves the dequeue() method call with an InterruptedException thrown. This exception is caught in the PoolThread.run() method, reported, and then the isStopped variable is checked. Since isStopped is now true, the PoolThread.run() will exit and the thread dies. -The Runnable will be dequeued by an idle PoolThread and executed. You can see this in the PoolThread.run() method. After execution the PoolThread loops and tries to dequeue a task again, until stopped. +可运行将闲置PoolThread离队并执行。你可以看到在PoolThread.run()方法。执行后PoolThread循环,并尝试再次出列任务,直到停止。 -To stop the ThreadPool the method ThreadPool.stop() is called. The stop called is noted internally in the isStopped member. Then each thread in the pool is stopped by calling PoolThread.stop(). Notice how the execute() method will throw an IllegalStateException if execute() is called after stop() has been called. +停止线程池的方法ThreadPool.stop()被调用。所谓停止在内部指出,在isStopped成员。然后在池中的每个线程通过调用PoolThread.stop停止()。注意execute()方法将如何抛出IllegalStateException如果执行()停止后称为()被调用。 -The threads will stop after finishing any task they are currently executing. Notice the this.interrupt() call in PoolThread.stop(). This makes sure that a thread blocked in a wait() call inside the taskQueue.dequeue() call breaks out of the wait() call, and leaves the dequeue() method call with an InterruptedException thrown. This exception is caught in the PoolThread.run() method, reported, and then the isStopped variable is checked. Since isStopped is now true, the PoolThread.run() will exit and the thread dies. \ No newline at end of file +整理他们目前正在执行的所有任务后,线程将停止。注意在PoolThread.stop的this.interrupt()()的调用。这将确保一个线程阻塞在taskQueue.dequeue()调用中断了wait()调用内部的wait()调用,并离开出列()方法调用抛出一个InterruptedException。这个异常被捕获在PoolThread.run()方法,报告,然后isStopped变量进行检查。由于isStopped现在是真,PoolThread.run()将退出与线程死亡。 From f588a9bf2bd6e823744f06f6fc4dbf91f6a13ed5 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 01:53:30 +0800 Subject: [PATCH 352/524] Published with https://stackedit.io/ --- .../21.\347\272\277\347\250\213\346\261\240.md" | 9 --------- 1 file changed, 9 deletions(-) diff --git "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" index 035bad8..47fa13f 100644 --- "a/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" +++ "b/Java-Concurrency/21.\347\272\277\347\250\213\346\261\240.md" @@ -81,13 +81,4 @@ public class PoolThread extends Thread { 当需要停止线程池可以调用`ThreadPool.stop()`方法,此时会有一个isStopped成员变量来标记线程池被停止。然后逐个调用线程池中线程的`PoolThread.stop()`方法。注意当线程池被停止后再调用`execute()`方法,则会抛出IllegaStateException异常。 - - - The threads will stop after finishing any task they are currently executing. Notice the this.interrupt() call in PoolThread.stop(). This makes sure that a thread blocked in a wait() call inside the taskQueue.dequeue() call breaks out of the wait() call, and leaves the dequeue() method call with an InterruptedException thrown. This exception is caught in the PoolThread.run() method, reported, and then the isStopped variable is checked. Since isStopped is now true, the PoolThread.run() will exit and the thread dies. - -可运行将闲置PoolThread离队并执行。你可以看到在PoolThread.run()方法。执行后PoolThread循环,并尝试再次出列任务,直到停止。 - -停止线程池的方法ThreadPool.stop()被调用。所谓停止在内部指出,在isStopped成员。然后在池中的每个线程通过调用PoolThread.stop停止()。注意execute()方法将如何抛出IllegalStateException如果执行()停止后称为()被调用。 - -整理他们目前正在执行的所有任务后,线程将停止。注意在PoolThread.stop的this.interrupt()()的调用。这将确保一个线程阻塞在taskQueue.dequeue()调用中断了wait()调用内部的wait()调用,并离开出列()方法调用抛出一个InterruptedException。这个异常被捕获在PoolThread.run()方法,报告,然后isStopped变量进行检查。由于isStopped现在是真,PoolThread.run()将退出与线程死亡。 From 95277f5d0d97aecaf3117c47b4687d942320c5e3 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 01:54:37 +0800 Subject: [PATCH 353/524] Published with https://stackedit.io/ From fc4b12640d96c528afce81e9e22d4ec8641e7b11 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 01:57:00 +0800 Subject: [PATCH 354/524] Published with https://stackedit.io/ --- ...20\345\220\214\346\255\245\345\231\250.md" | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index 89aa638..41bb786 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -15,12 +15,13 @@ Test and Set Method Set Method Not all synchronizers have all of these parts, and those that have may not have them exactly as they are described here. Usually you can find one or more of these parts, though. -State +##State The state of a synchronizer is used by the access condition to determine if a thread can be granted access. In a Lock the state is kept in a boolean saying whether the Lock is locked or not. In a Bounded Semaphore the internal state is kept in a counter (int) and an upper bound (int) which state the current number of "takes" and the maximum number of "takes". In a Blocking Queue the state is kept in the List of elements in the queue and the maximum queue size (int) member (if any). Here are two code snippets from both Lock and a BoundedSemaphore. The state code is marked in bold. +```Java public class Lock{ //state is kept here @@ -53,7 +54,9 @@ public class BoundedSemaphore { } ... } -Access Condition +``` + +##Access Condition The access conditions is what determines if a thread calling a test-and-set-state method can be allowed to set the state or not. The access condition is typically based on the state of the synchronizer. The access condition is typically checked in a while loop to guard against Spurious Wakeups. When the access condition is evaluated it is either true or false. @@ -61,6 +64,7 @@ In a Lock the access condition simply checks the value of the isLocked member va Here are two code snippets of a Lock and a BoundedSemaphore with the access condition marked in bold. Notice how the conditions is always checked inside a while loop. +```Java public class Lock{ private boolean isLocked = false; @@ -98,7 +102,9 @@ public class BoundedSemaphore { this.notify(); } } -State Changes +``` + +##State Changes Once a thread gains access to the critical section it has to change the state of the synchronizer to (possibly) block other threads from entering it. In other words, the state needs to reflect the fact that a thread is now executing inside the critical section. This should affect the access conditions of other threads attempting to gain access. @@ -106,6 +112,7 @@ In a Lock the state change is the code setting isLocked = true. In a semaphore i Here are two code snippets with the state change code marked in bold: +```Java public class Lock{ private boolean isLocked = false; @@ -147,15 +154,20 @@ public class BoundedSemaphore { this.notify(); } } -Notification Strategy +`` + +##Notification Strategy Once a thread has changed the state of a synchronizer it may sometimes need to notify other waiting threads about the state change. Perhaps this state change might turn the access condition true for other threads. Notification Strategies typically fall into three categories. +``` Notify all waiting threads. Notify 1 random of N waiting threads. Notify 1 specific of N waiting thread. +``` + Notifying all waiting threads is pretty easy. All waiting threads call wait() on the same object. Once a thread want to notify the waiting threads it calls notifyAll() on the object the waiting threads called wait() on. Notifying a single random waiting thread is also pretty easy. Just have the notifying thread call notify() on the object the waiting threads have called wait() on. Calling notify makes no guarantee about which of the waiting threads will be notified. Hence the term "random waiting thread". @@ -164,6 +176,7 @@ Sometimes you may need to notify a specific rather than a random waiting thread. Below is a code snippet with the notification strategy (notify 1 random waiting thread) marked in bold: +```Java public class Lock{ private boolean isLocked = false; @@ -182,7 +195,9 @@ public class Lock{ notify(); //notification strategy } } -Test and Set Method +``` + +##Test and Set Method Synchronizer most often have two types of methods of which test-and-set is the first type (set is the other). Test-and-set means that the thread calling this method tests the internal state of the synchronizer against the access condition. If the condition is met the thread sets the internal state of the synchronizer to reflect that the thread has gained access. @@ -198,6 +213,7 @@ If access condition is not met, wait If access condition is met, set state, and notify waiting threads if necessary The lockWrite() method of a ReadWriteLock class shown below is an example of a test-and-set method. Threads calling lockWrite() first sets the state before the test (writeRequests++). Then it tests the internal state against the access condition in the canGrantWriteAccess() method. If the test succeeds the internal state is set again before the method is exited. Notice that this method does not notify waiting threads. +```Java public class ReadWriteLock{ private Map readingThreads = new HashMap (); @@ -223,9 +239,12 @@ public class ReadWriteLock{ ... } +``` + The BoundedSemaphore class shown below has two test-and-set methods: take() and release(). Both methods test and sets the internal state. +```Java public class BoundedSemaphore { private int signals = 0; private int bound = 0; @@ -248,7 +267,9 @@ public class BoundedSemaphore { } } -Set Method +``` + +##Set Method The set method is the second type of method that synchronizers often contain. The set method just sets the internal state of the synchronizer without testing it first. A typical example of a set method is the unlock() method of a Lock class. A thread holding the lock can always unlock it without having to test if the Lock is unlocked. @@ -258,6 +279,7 @@ Set internal state Notify waiting threads Here is an example unlock() method: +```Java public class Lock{ private boolean isLocked = false; @@ -267,4 +289,5 @@ public class Lock{ notify(); } -} \ No newline at end of file +} +``` \ No newline at end of file From 435dd728f85e4301c071851ec5991c792a6c6b97 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 01:58:57 +0800 Subject: [PATCH 355/524] Published with https://stackedit.io/ --- ...11\226\346\236\220\345\220\214\346\255\245\345\231\250.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index 41bb786..f843bf4 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -154,7 +154,7 @@ public class BoundedSemaphore { this.notify(); } } -`` +``` ##Notification Strategy @@ -162,7 +162,7 @@ Once a thread has changed the state of a synchronizer it may sometimes need to n Notification Strategies typically fall into three categories. -``` +```Java Notify all waiting threads. Notify 1 random of N waiting threads. Notify 1 specific of N waiting thread. From c497558f016d25ce53b0cdde0a5b5fa0250f026c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 02:03:10 +0800 Subject: [PATCH 356/524] Published with https://stackedit.io/ --- ...26\346\236\220\345\220\214\346\255\245\345\231\250.md" | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index f843bf4..23fe3e9 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -15,7 +15,7 @@ Test and Set Method Set Method Not all synchronizers have all of these parts, and those that have may not have them exactly as they are described here. Usually you can find one or more of these parts, though. -##State +##状态(State) The state of a synchronizer is used by the access condition to determine if a thread can be granted access. In a Lock the state is kept in a boolean saying whether the Lock is locked or not. In a Bounded Semaphore the internal state is kept in a counter (int) and an upper bound (int) which state the current number of "takes" and the maximum number of "takes". In a Blocking Queue the state is kept in the List of elements in the queue and the maximum queue size (int) member (if any). @@ -56,7 +56,7 @@ public class BoundedSemaphore { } ``` -##Access Condition +##访问条件(Access Condition) The access conditions is what determines if a thread calling a test-and-set-state method can be allowed to set the state or not. The access condition is typically based on the state of the synchronizer. The access condition is typically checked in a while loop to guard against Spurious Wakeups. When the access condition is evaluated it is either true or false. @@ -104,7 +104,7 @@ public class BoundedSemaphore { } ``` -##State Changes +##状态变化(State Changes) Once a thread gains access to the critical section it has to change the state of the synchronizer to (possibly) block other threads from entering it. In other words, the state needs to reflect the fact that a thread is now executing inside the critical section. This should affect the access conditions of other threads attempting to gain access. @@ -156,7 +156,7 @@ public class BoundedSemaphore { } ``` -##Notification Strategy +##通知策略(Notification Strategy) Once a thread has changed the state of a synchronizer it may sometimes need to notify other waiting threads about the state change. Perhaps this state change might turn the access condition true for other threads. From 4895d88323f8ccf65e1cc126a73dc3e198ec5da9 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 02:05:39 +0800 Subject: [PATCH 357/524] Published with https://stackedit.io/ --- ...6\220\345\220\214\346\255\245\345\231\250.md" | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index 23fe3e9..5a42d0f 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -117,8 +117,7 @@ public class Lock{ private boolean isLocked = false; - public synchronized void lock() - throws InterruptedException{ + public synchronized void lock() throws InterruptedException{ while(isLocked){ wait(); } @@ -181,8 +180,7 @@ public class Lock{ private boolean isLocked = false; - public synchronized void lock() - throws InterruptedException{ + public synchronized void lock() throws InterruptedException{ while(isLocked){ //wait strategy - related to notification strategy wait(); @@ -215,26 +213,24 @@ The lockWrite() method of a ReadWriteLock class shown below is an example of a t ```Java public class ReadWriteLock{ - private Map readingThreads = - new HashMap (); + private Map readingThreads = new HashMap (); private int writeAccesses = 0; private int writeRequests = 0; private Thread writingThread = null; ... - - public synchronized void lockWrite() throws InterruptedException{ + public synchronized void lockWrite() throws InterruptedException{ writeRequests++; Thread callingThread = Thread.currentThread(); while(! canGrantWriteAccess(callingThread)){ - wait(); + wait(); } writeRequests--; writeAccesses++; writingThread = callingThread; - } + } ... From 7bc694c5074e0a8fb1a8bf00e58ff59d710823d2 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 02:06:15 +0800 Subject: [PATCH 358/524] Published with https://stackedit.io/ --- ...20\345\220\214\346\255\245\345\231\250.md" | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index 5a42d0f..30bb9b5 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -250,17 +250,17 @@ public class BoundedSemaphore { } - public synchronized void take() throws InterruptedException{ - while(this.signals == bound) wait(); - this.signals++; - this.notify(); - } - - public synchronized void release() throws InterruptedException{ - while(this.signals == 0) wait(); - this.signals--; - this.notify(); - } + public synchronized void take() throws InterruptedException{ + while(this.signals == bound) wait(); + this.signals++; + this.notify(); + } + + public synchronized void release() throws InterruptedException{ + while(this.signals == 0) wait(); + this.signals--; + this.notify(); + } } ``` @@ -280,10 +280,10 @@ public class Lock{ private boolean isLocked = false; - public synchronized void unlock(){ - isLocked = false; + public synchronized void unlock(){ + isLocked = false; notify(); - } + } } ``` \ No newline at end of file From c8e31c50260c29430cbab8263d12ff0d82b24db6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 02:21:18 +0800 Subject: [PATCH 359/524] Published with https://stackedit.io/ --- ...11\226\346\236\220\345\220\214\346\255\245\345\231\250.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index 30bb9b5..fd5a369 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -1,9 +1,9 @@ #22.剖析同步器 -Even if many synchronizers (locks, semaphores, blocking queue etc.) are different in function, they are often not that different in their internal design. In other words, they consist of the same (or similar) basic parts internally. Knowing these basic parts can be a great help when designing synchronizers. It is these parts this text looks closer at. +虽然很多同步器(锁、信号量、阻塞队列等)在使用方式上不同,但是它们的内部设计上并非总不一样。换言之,**它们内部都是由相同或相似的基本部件组成**。了解这些基本部件对设计同步器非常有帮助,这正是本文将要讲的内容。 -Note: The content of this text is a part result of a M.Sc. student project at the IT University of Copenhagen in the spring 2004 by Jakob Jenkov, Toke Johansen and Lars Bjørn. During this project we asked Doug Lea if he knew of similar work. Interestingly he had come up with similar conclusions independently of this project during the development of the Java 5 concurrency utilities. Doug Lea's work, I believe, is described in the book "Java Concurrency in Practice". This book also contains a chapter with the title "Anatomy of a Synchronizer" with content similar to this text, though not exactly the same. +(Note: The content of this text is a part result of a M.Sc. student project at the IT University of Copenhagen in the spring 2004 by Jakob Jenkov, Toke Johansen and Lars Bjørn. During this project we asked Doug Lea if he knew of similar work. Interestingly he had come up with similar conclusions independently of this project during the development of the Java 5 concurrency utilities. Doug Lea's work, I believe, is described in the book "Java Concurrency in Practice". This book also contains a chapter with the title "Anatomy of a Synchronizer" with content similar to this text, though not exactly the same.) The purpose of most (if not all) synchronizers is to guard some area of the code (critical section) from concurrent access by threads. To do this the following parts are often needed in a synchronizer: From 10494c6fd71260665a45672aa1788782d8f8d388 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 02:42:27 +0800 Subject: [PATCH 360/524] Published with https://stackedit.io/ --- ...20\345\220\214\346\255\245\345\231\250.md" | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index fd5a369..5ed2e9e 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -5,18 +5,22 @@ (Note: The content of this text is a part result of a M.Sc. student project at the IT University of Copenhagen in the spring 2004 by Jakob Jenkov, Toke Johansen and Lars Bjørn. During this project we asked Doug Lea if he knew of similar work. Interestingly he had come up with similar conclusions independently of this project during the development of the Java 5 concurrency utilities. Doug Lea's work, I believe, is described in the book "Java Concurrency in Practice". This book also contains a chapter with the title "Anatomy of a Synchronizer" with content similar to this text, though not exactly the same.) -The purpose of most (if not all) synchronizers is to guard some area of the code (critical section) from concurrent access by threads. To do this the following parts are often needed in a synchronizer: -State -Access Condition -State Changes -Notification Strategy -Test and Set Method -Set Method -Not all synchronizers have all of these parts, and those that have may not have them exactly as they are described here. Usually you can find one or more of these parts, though. +绝大部分同步器的目的都是为了在多线程并发环境中保护**临界区(critical section)**。为了实现这些功能,同步器需要包含以下部件: + +* 状态(State) +* 访问条件(Access Condition) +* 状态变化(State Changes) +* 通知策略(Notification Strategy) +* Test and Set Method +* Set Method + +并不是所有的同步器都包含以上组件,也不是所有的部件都如这里描述的完全一样,然而,你还是可以中找到一个或更多的部件。 ##状态(State) + + The state of a synchronizer is used by the access condition to determine if a thread can be granted access. In a Lock the state is kept in a boolean saying whether the Lock is locked or not. In a Bounded Semaphore the internal state is kept in a counter (int) and an upper bound (int) which state the current number of "takes" and the maximum number of "takes". In a Blocking Queue the state is kept in the List of elements in the queue and the maximum queue size (int) member (if any). Here are two code snippets from both Lock and a BoundedSemaphore. The state code is marked in bold. From 55c379e931605e5efb2071f95368526aef711af1 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 03:06:18 +0800 Subject: [PATCH 361/524] Published with https://stackedit.io/ --- ...26\346\236\220\345\220\214\346\255\245\345\231\250.md" | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index 5ed2e9e..41ff374 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -19,17 +19,15 @@ ##状态(State) - - The state of a synchronizer is used by the access condition to determine if a thread can be granted access. In a Lock the state is kept in a boolean saying whether the Lock is locked or not. In a Bounded Semaphore the internal state is kept in a counter (int) and an upper bound (int) which state the current number of "takes" and the maximum number of "takes". In a Blocking Queue the state is kept in the List of elements in the queue and the maximum queue size (int) member (if any). -Here are two code snippets from both Lock and a BoundedSemaphore. The state code is marked in bold. +下面两段代码片段分别来自于**Lock**类和**BoundedSemaphore**类。状态的代码使用粗体标识: ```Java public class Lock{ - //state is kept here - private boolean isLocked = false; + **//state is kept here** + **private boolean isLocked = false;** public synchronized void lock() throws InterruptedException{ From 38599dfc1262ef22ebbcfb46fb5d3993898d861c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 03:07:13 +0800 Subject: [PATCH 362/524] Published with https://stackedit.io/ --- ...\236\220\345\220\214\346\255\245\345\231\250.md" | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index 41ff374..e25c5bf 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -21,16 +21,15 @@ The state of a synchronizer is used by the access condition to determine if a thread can be granted access. In a Lock the state is kept in a boolean saying whether the Lock is locked or not. In a Bounded Semaphore the internal state is kept in a counter (int) and an upper bound (int) which state the current number of "takes" and the maximum number of "takes". In a Blocking Queue the state is kept in the List of elements in the queue and the maximum queue size (int) member (if any). -下面两段代码片段分别来自于**Lock**类和**BoundedSemaphore**类。状态的代码使用粗体标识: +下面两段代码片段分别来自于**Lock**类和**BoundedSemaphore**类。状态的代码注释标识: ```Java public class Lock{ - **//state is kept here** - **private boolean isLocked = false;** + //state is kept here + private boolean isLocked = false; - public synchronized void lock() - throws InterruptedException{ + public synchronized void lock() throws InterruptedException{ while(isLocked){ wait(); } @@ -42,8 +41,8 @@ public class Lock{ public class BoundedSemaphore { //state is kept here - private int signals = 0; - private int bound = 0; + private int signals = 0; + private int bound = 0; public BoundedSemaphore(int upperBound){ this.bound = upperBound; From c3be38c3168b3f9cfd3a5564248a673ee3b92ae1 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 03:09:22 +0800 Subject: [PATCH 363/524] Published with https://stackedit.io/ --- ...236\220\345\220\214\346\255\245\345\231\250.md" | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index e25c5bf..c26d9a0 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -59,7 +59,7 @@ public class BoundedSemaphore { ##访问条件(Access Condition) -The access conditions is what determines if a thread calling a test-and-set-state method can be allowed to set the state or not. The access condition is typically based on the state of the synchronizer. The access condition is typically checked in a while loop to guard against Spurious Wakeups. When the access condition is evaluated it is either true or false. +The access conditions is what determines if a thread calling a **test-and-set-state** method can be allowed to set the state or not. The access condition is typically based on the state of the synchronizer. The access condition is typically checked in a while loop to guard against Spurious Wakeups. When the access condition is evaluated it is either true or false. In a Lock the access condition simply checks the value of the isLocked member variable. In a Bounded Semaphore there are actually two access conditions depending on whether you are trying to "take" or "release" the semaphore. If a thread tries to take the semaphore the signals variable is checked against the upper bound. If a thread tries to release the semaphore the signals variable is checked against 0. @@ -67,11 +67,9 @@ Here are two code snippets of a Lock and a BoundedSemaphore with the access cond ```Java public class Lock{ - private boolean isLocked = false; - public synchronized void lock() - throws InterruptedException{ + public synchronized void lock() throws InterruptedException{ //access condition while(isLocked){ wait(); @@ -258,9 +256,11 @@ public class BoundedSemaphore { } public synchronized void release() throws InterruptedException{ - while(this.signals == 0) wait(); - this.signals--; - this.notify(); + while(this.signals == 0) { + wait(); + } + this.signals--; + this.notify(); } } From 213c7761dfbbca9dd93a74d6973f109d05390396 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 03:09:43 +0800 Subject: [PATCH 364/524] Published with https://stackedit.io/ --- ...5\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" | 1 - 1 file changed, 1 deletion(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index c26d9a0..e1fb969 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -278,7 +278,6 @@ Here is an example unlock() method: ```Java public class Lock{ - private boolean isLocked = false; public synchronized void unlock(){ From 2626ec4fd115c95adb14755eea11079e2ea7c3ae Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 03:10:20 +0800 Subject: [PATCH 365/524] Published with https://stackedit.io/ --- ...26\346\236\220\345\220\214\346\255\245\345\231\250.md" | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index e1fb969..ab38472 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -250,9 +250,11 @@ public class BoundedSemaphore { public synchronized void take() throws InterruptedException{ - while(this.signals == bound) wait(); - this.signals++; - this.notify(); + while(this.signals == bound) { + wait(); + } + this.signals++; + this.notify(); } public synchronized void release() throws InterruptedException{ From 29f3771665f6f1fd2e19faa716f38e85ea722d2a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 03:18:55 +0800 Subject: [PATCH 366/524] Published with https://stackedit.io/ --- ...\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" index ab38472..a9b42ef 100644 --- "a/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" +++ "b/Java-Concurrency/22.\345\211\226\346\236\220\345\220\214\346\255\245\345\231\250.md" @@ -59,7 +59,7 @@ public class BoundedSemaphore { ##访问条件(Access Condition) -The access conditions is what determines if a thread calling a **test-and-set-state** method can be allowed to set the state or not. The access condition is typically based on the state of the synchronizer. The access condition is typically checked in a while loop to guard against Spurious Wakeups. When the access condition is evaluated it is either true or false. +**访问条件(Access Condition)**用来决定线程调用**test-and-set-state**方法是否可以改变**状态(State)**。访问条件通常基于同步器的状态。访问条件通常在while循环中进行判断以防止**假唤醒(Spurious Wakeups)**。当对访问条件进行判断时,只返回true或false。 In a Lock the access condition simply checks the value of the isLocked member variable. In a Bounded Semaphore there are actually two access conditions depending on whether you are trying to "take" or "release" the semaphore. If a thread tries to take the semaphore the signals variable is checked against the upper bound. If a thread tries to release the semaphore the signals variable is checked against 0. From c444902cb5c298587cfdc1feb199df87724e4d8d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 09:55:56 +0800 Subject: [PATCH 367/524] Published with https://stackedit.io/ From c05d7216f520433b134662c1393206b4cade9782 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 10:06:52 +0800 Subject: [PATCH 368/524] Published with https://stackedit.io/ --- .../06.Java NIO\351\200\211\346\213\251\345\231\250.md" | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index bf8a103..634f305 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -102,7 +102,7 @@ Channel channel = selectionKey.channel(); Selector selector = selectionKey.selector(); ``` -###Attaching Objects +###附加对象(Attaching Objects) You can attach an object to a SelectionKey this is a handy way of recognizing a given channel, or attaching further information to the channel. For instance, you may attach the Buffer you are using with the channel, or an object containing more aggregate data. Here is how you attach objects: @@ -120,7 +120,7 @@ SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); ##Selecting Channels via a Selector - 当向选择器注册一个或多个通道后,可以调用`Selector.slect(...)`方法,这个返回会当前已经就绪的通道(说明该通道有选择器监听的事件就绪)的个数。换言之,如果选择器监听了一个通道的读事件,当该通道有数据可读时,`Selector.select(...)`操作就会返回 1。 +当向选择器注册一个或多个通道后,可以调用`Selector.slect(...)`方法,这个返回会当前已经就绪的通道(说明该通道有选择器监听的事件就绪)的个数。换言之,如果选择器监听了一个通道的读事件,当该通道有数据可读时,`Selector.select(...)`操作就会返回 1。 有多个重载的`select()`方法: @@ -144,8 +144,6 @@ SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); Set selectedKeys = selector.selectedKeys(); ``` -当你通过`SelectableChannel.register()`注册通道时,返回一个SeletionKey对象。 - When you register a channel with a Selector the Channel.register() method returns a SelectionKey object. This key represents that channels registration with that selector. It is these keys you can access via the selectedKeySet() method. From the SelectionKey. You can iterate this selected key set to access the ready channels. Here is how that looks: From 94c2f07273ff06bf68e2d3c9b436d55204fbf114 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 10:07:52 +0800 Subject: [PATCH 369/524] Published with https://stackedit.io/ --- "Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" index 634f305..5af294c 100644 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -176,7 +176,7 @@ while(keyIterator.hasNext()) { This loop iterates the keys in the selected key set. For each key it tests the key to determine what the channel referenced by the key is ready for. -Notice the keyIterator.remove() call at the end of each iteration. The Selector does not remove the SelectionKey instances from the selected key set itself. You have to do this, when you are done processing the channel. The next time the channel becomes "ready" the Selector will add it to the selected key set again. +Notice the `keyIterator.remove()` call at the end of each iteration. The Selector does not remove the SelectionKey instances from the selected key set itself. You have to do this, when you are done processing the channel. The next time the channel becomes "ready" the Selector will add it to the selected key set again. The channel returned by the SelectionKey.channel() method should be cast to the channel you need to work with, e.g a ServerSocketChannel or SocketChannel etc. From 1b2edd6befdbc5dc1e5365d580d8fe9d686d69c8 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 10:09:24 +0800 Subject: [PATCH 370/524] Published with https://stackedit.io/ --- ...IO\351\200\211\346\213\251\345\231\250.md" | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 "Java-NIO/07.Java NIO\351\200\211\346\213\251\345\231\250.md" diff --git "a/Java-NIO/07.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/07.Java NIO\351\200\211\346\213\251\345\231\250.md" new file mode 100644 index 0000000..e11a4f6 --- /dev/null +++ "b/Java-NIO/07.Java NIO\351\200\211\346\213\251\345\231\250.md" @@ -0,0 +1,235 @@ +#07.Java NIO选择器 + +选择器(Selector)是Java NIO中的一个组件,它用于检测一个或多个通道,并确定哪些通道可以进行读、写。这就是为什么Java NIO中可以使用单个线程对多个通道或网络连接进行管理。 + + +##为何要使用选择器(Why Use a Selector?) + +使用选择器的优势在于:**使用单个线程就可以对多个管道进行操作,从而可以减少处理通道的线程数量**。实际上,你可以仅仅使用一个线程来处理所有的通道。在操作系统中,线程的切换是非常昂贵的,并且,每个线程需要消耗一定的系统资源(例如内存)。因此,线程使用越少越好。 + +不过,随着操作系统软硬件的更新迭代,多线程的开销越来越小,性能也越来越优异。而事实上,如果计算机拥有多个CPU内核,这时候如果不采用多线程,反而是对CPU资源的浪费。然而,这已不属于本教程讨论的范畴。 + +下面的图片描绘了如何使用一个选择器来处理3个通道: + + + +##创建选择器(Creating a Selector) + +可以通过`Selector.open()`方法来创建选择器: + +```Java +Selector selector = Selector.open(); +``` + +#Registering Channels with the Selector + +为了让选择器能够处理通道,必须向选择器注册需要处理的通道,调用`SelectableChannel.register()`方法来完成注册: + +``` +channel.configureBlocking(false); + +SelectionKey key = channel.register(selector, SelectionKey.OP_READ); +``` + +注册的通道必须先设置为**非阻塞模式(non-blocking mode)**。由于**FileChannel**不能设置为非阻塞模式,所以FileChannel不能进行注册,而**SocketChanne**l则可以。 + +注意`SelectableChannel.register()`方法的第二个参数。这个参数代表着**选择器需要监听通道的事件类型**。总共有四种不同的事件类型: + +通道**触发一个事件**,我们称之为**事件就绪**。所以,如果通道跟远程服务器建立了连接,称之为**连接就绪**;服务器socket接受客户端连接,称为**接收就绪**;通道中有数据可读,称为**读就绪**,可向通道中写数据,称为**写就绪**。 + +以上四个事件分别由`SelectionKey`类中的四个常量来表示: + +```Java +SelectionKey.OP_CONNECT +SelectionKey.OP_ACCEPT +SelectionKey.OP_READ +SelectionKey.OP_WRITE +``` + +如果需要监听多个事件,可以使用OR操作符: + +```Java +int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; +``` +由于SelectionKey中是四个常量OP\_READ、OP\_WRITE、OP\_CONNECT、OP\_ACCEPTF分别用二进制0001、0010、0100、1000表示,所以可以通过interestSet中的二进制判断监听的事件类型。 + +##SelectionKey's + +上面的例子中,当调用`SelectableChannel.register()`向选择器注册通道后,该返回会返回一个`SeletionKey`对象。该`SelectionKey`对象包含以下属性: + +``` +The interest set(监听的事件集合) +The ready set(就绪的事件集合) +The Channel(通道) +The Selector(选择器) +An attached object (optional) +``` + +###Interest Set(监听的事件集合) + +InterestSet表示的是监听的时间集合,可以通过`SelctionKey.interestOPs()`方法获取监听的时间集合,它是一个int类型数据,由于SelectionKey中是四个常量OP\_READ、OP\_WRITE、OP\_CONNECT、OP\_ACCEPTF分别用二进制0001、0010、0100、1000表示,所以,我们可以通过**按位与**操作判断监听的事件类型: + +```Java +int interestSet = selectionKey.interestOps(); + +boolean isInterestedInAccept = interestSet & SelectionKey.OP_ACCEPT; +boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT; +boolean isInterestedInRead = interestSet & SelectionKey.OP_READ; +boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE; +``` + +###Ready Set(就绪集合) + +可以通过`SelectionKey.readyOps()`方法获取就绪集合。同样地,通过按位与操作判断就绪的事件类型: + +```Java +int readySet = selectionKey.readyOps(); + +selectionKey.isAcceptable(); +selectionKey.isConnectable(); +selectionKey.isReadable(); +selectionKey.isWritable(); +``` + + +###Channel + Selector(通道和选择器) + +Accessing the channel + selector from the SelectionKey is trivial. Here is how it's done: + +```Java +Channel channel = selectionKey.channel(); + +Selector selector = selectionKey.selector(); +``` + +###附加对象(Attaching Objects) + +You can attach an object to a SelectionKey this is a handy way of recognizing a given channel, or attaching further information to the channel. For instance, you may attach the Buffer you are using with the channel, or an object containing more aggregate data. Here is how you attach objects: + +```Java +selectionKey.attach(theObject); + +Object attachedObj = selectionKey.attachment(); +``` + +You can also attach an object already while registering the Channel with the Selector, in the register() method. Here is how that looks: + +```Java +SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); +``` + +##Selecting Channels via a Selector + +当向选择器注册一个或多个通道后,可以调用`Selector.slect(...)`方法,这个返回会当前已经就绪的通道(说明该通道有选择器监听的事件就绪)的个数。换言之,如果选择器监听了一个通道的读事件,当该通道有数据可读时,`Selector.select(...)`操作就会返回 1。 + +有多个重载的`select()`方法: + +> int select() +> int select(long timeout) +> int selectNow() + +`select()`方法会阻塞直到有通道事件就绪。 + +`select(long timeout)`方法会阻塞直到有通道事件就绪或超时。 + +`selectNow()`方法不管有没有通道事件就绪,都会立即返回。 + +`select()`返回值为int类型,代表从上次调用`select()`方法到这次的就绪通道数量。当你调用select返回1时,则代表上次调用select方法到这次调用之间有一个通道变成了就绪状态,然后,再次调用select方法,如果返回值为1,则说明又有一个通道变成了就绪状态。如果你没对第一个就绪通道进行处理,则此时共有两个就绪通道,虽然最后一次select的返回值为1。 + +###selectedKeys() + +当你调用select()方法返回值不为0时,则说明有一个或多个通道已经就绪。你可以通过调用`selector.selectedKeys()`获取就绪的通道: + +```Java +Set selectedKeys = selector.selectedKeys(); +``` + +When you register a channel with a Selector the Channel.register() method returns a SelectionKey object. This key represents that channels registration with that selector. It is these keys you can access via the selectedKeySet() method. From the SelectionKey. + +You can iterate this selected key set to access the ready channels. Here is how that looks: + +```Java +Set selectedKeys = selector.selectedKeys(); + +Iterator keyIterator = selectedKeys.iterator(); + +while(keyIterator.hasNext()) { + + SelectionKey key = keyIterator.next(); + + if(key.isAcceptable()) { + // a connection was accepted by a ServerSocketChannel. + + } else if (key.isConnectable()) { + // a connection was established with a remote server. + + } else if (key.isReadable()) { + // a channel is ready for reading + + } else if (key.isWritable()) { + // a channel is ready for writing + } + + keyIterator.remove(); +} +``` + +This loop iterates the keys in the selected key set. For each key it tests the key to determine what the channel referenced by the key is ready for. + +Notice the `keyIterator.remove()` call at the end of each iteration. The Selector does not remove the SelectionKey instances from the selected key set itself. You have to do this, when you are done processing the channel. The next time the channel becomes "ready" the Selector will add it to the selected key set again. + +The channel returned by the SelectionKey.channel() method should be cast to the channel you need to work with, e.g a ServerSocketChannel or SocketChannel etc. + +###wakeUp() + +A thread that has called the select() method which is blocked, can be made to leave the select() method, even if no channels are yet ready. This is done by having a different thread call the Selector.wakeup() method on the Selector which the first thread has called select() on. The thread waiting inside select() will then return immediately. + +If a different thread calls wakeup() and no thread is currently blocked inside select(), the next thread that calls select() will "wake up" immediately. + +###close() + +When you are finished with the Selector you call its close() method. This closes the Selector and invalidates all SelectionKey instances registered with this Selector. The channels themselves are not closed. + +##Full Selector Example + +Here is a full example which opens a Selector, registers a channel with it (the channel instantiation is left out), and keeps monitoring the Selector for "readiness" of the four events (accept, connect, read, write). + +Selector selector = Selector.open(); + +channel.configureBlocking(false); + +SelectionKey key = channel.register(selector, SelectionKey.OP_READ); + +```Java +while(true) { + + int readyChannels = selector.select(); + + if(readyChannels == 0) continue; + + + Set selectedKeys = selector.selectedKeys(); + + Iterator keyIterator = selectedKeys.iterator(); + + while(keyIterator.hasNext()) { + + SelectionKey key = keyIterator.next(); + + if(key.isAcceptable()) { + // a connection was accepted by a ServerSocketChannel. + + } else if (key.isConnectable()) { + // a connection was established with a remote server. + + } else if (key.isReadable()) { + // a channel is ready for reading + + } else if (key.isWritable()) { + // a channel is ready for writing + } + + keyIterator.remove(); + } +} +``` \ No newline at end of file From 75669b9d813bd147f5582a52b6d1146a76bab527 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 10:09:43 +0800 Subject: [PATCH 371/524] =?UTF-8?q?Delete=2006.Java=20NIO=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E5=99=A8.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...IO\351\200\211\346\213\251\345\231\250.md" | 235 ------------------ 1 file changed, 235 deletions(-) delete mode 100644 "Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" diff --git "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" "b/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" deleted file mode 100644 index 5af294c..0000000 --- "a/Java-NIO/06.Java NIO\351\200\211\346\213\251\345\231\250.md" +++ /dev/null @@ -1,235 +0,0 @@ -#06.Java NIO选择器 - -选择器(Selector)是Java NIO中的一个组件,它用于检测一个或多个通道,并确定哪些通道可以进行读、写。这就是为什么Java NIO中可以使用单个线程对多个通道或网络连接进行管理。 - - -##为何要使用选择器(Why Use a Selector?) - -使用选择器的优势在于:**使用单个线程就可以对多个管道进行操作,从而可以减少处理通道的线程数量**。实际上,你可以仅仅使用一个线程来处理所有的通道。在操作系统中,线程的切换是非常昂贵的,并且,每个线程需要消耗一定的系统资源(例如内存)。因此,线程使用越少越好。 - -不过,随着操作系统软硬件的更新迭代,多线程的开销越来越小,性能也越来越优异。而事实上,如果计算机拥有多个CPU内核,这时候如果不采用多线程,反而是对CPU资源的浪费。然而,这已不属于本教程讨论的范畴。 - -下面的图片描绘了如何使用一个选择器来处理3个通道: - - - -##创建选择器(Creating a Selector) - -可以通过`Selector.open()`方法来创建选择器: - -```Java -Selector selector = Selector.open(); -``` - -#Registering Channels with the Selector - -为了让选择器能够处理通道,必须向选择器注册需要处理的通道,调用`SelectableChannel.register()`方法来完成注册: - -``` -channel.configureBlocking(false); - -SelectionKey key = channel.register(selector, SelectionKey.OP_READ); -``` - -注册的通道必须先设置为**非阻塞模式(non-blocking mode)**。由于**FileChannel**不能设置为非阻塞模式,所以FileChannel不能进行注册,而**SocketChanne**l则可以。 - -注意`SelectableChannel.register()`方法的第二个参数。这个参数代表着**选择器需要监听通道的事件类型**。总共有四种不同的事件类型: - -通道**触发一个事件**,我们称之为**事件就绪**。所以,如果通道跟远程服务器建立了连接,称之为**连接就绪**;服务器socket接受客户端连接,称为**接收就绪**;通道中有数据可读,称为**读就绪**,可向通道中写数据,称为**写就绪**。 - -以上四个事件分别由`SelectionKey`类中的四个常量来表示: - -```Java -SelectionKey.OP_CONNECT -SelectionKey.OP_ACCEPT -SelectionKey.OP_READ -SelectionKey.OP_WRITE -``` - -如果需要监听多个事件,可以使用OR操作符: - -```Java -int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; -``` -由于SelectionKey中是四个常量OP\_READ、OP\_WRITE、OP\_CONNECT、OP\_ACCEPTF分别用二进制0001、0010、0100、1000表示,所以可以通过interestSet中的二进制判断监听的事件类型。 - -##SelectionKey's - -上面的例子中,当调用`SelectableChannel.register()`向选择器注册通道后,该返回会返回一个`SeletionKey`对象。该`SelectionKey`对象包含以下属性: - -``` -The interest set(监听的事件集合) -The ready set(就绪的事件集合) -The Channel(通道) -The Selector(选择器) -An attached object (optional) -``` - -###Interest Set(监听的事件集合) - -InterestSet表示的是监听的时间集合,可以通过`SelctionKey.interestOPs()`方法获取监听的时间集合,它是一个int类型数据,由于SelectionKey中是四个常量OP\_READ、OP\_WRITE、OP\_CONNECT、OP\_ACCEPTF分别用二进制0001、0010、0100、1000表示,所以,我们可以通过**按位与**操作判断监听的事件类型: - -```Java -int interestSet = selectionKey.interestOps(); - -boolean isInterestedInAccept = interestSet & SelectionKey.OP_ACCEPT; -boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT; -boolean isInterestedInRead = interestSet & SelectionKey.OP_READ; -boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE; -``` - -###Ready Set(就绪集合) - -可以通过`SelectionKey.readyOps()`方法获取就绪集合。同样地,通过按位与操作判断就绪的事件类型: - -```Java -int readySet = selectionKey.readyOps(); - -selectionKey.isAcceptable(); -selectionKey.isConnectable(); -selectionKey.isReadable(); -selectionKey.isWritable(); -``` - - -###Channel + Selector(通道和选择器) - -Accessing the channel + selector from the SelectionKey is trivial. Here is how it's done: - -```Java -Channel channel = selectionKey.channel(); - -Selector selector = selectionKey.selector(); -``` - -###附加对象(Attaching Objects) - -You can attach an object to a SelectionKey this is a handy way of recognizing a given channel, or attaching further information to the channel. For instance, you may attach the Buffer you are using with the channel, or an object containing more aggregate data. Here is how you attach objects: - -```Java -selectionKey.attach(theObject); - -Object attachedObj = selectionKey.attachment(); -``` - -You can also attach an object already while registering the Channel with the Selector, in the register() method. Here is how that looks: - -```Java -SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); -``` - -##Selecting Channels via a Selector - -当向选择器注册一个或多个通道后,可以调用`Selector.slect(...)`方法,这个返回会当前已经就绪的通道(说明该通道有选择器监听的事件就绪)的个数。换言之,如果选择器监听了一个通道的读事件,当该通道有数据可读时,`Selector.select(...)`操作就会返回 1。 - -有多个重载的`select()`方法: - -> int select() -> int select(long timeout) -> int selectNow() - -`select()`方法会阻塞直到有通道事件就绪。 - -`select(long timeout)`方法会阻塞直到有通道事件就绪或超时。 - -`selectNow()`方法不管有没有通道事件就绪,都会立即返回。 - -`select()`返回值为int类型,代表从上次调用`select()`方法到这次的就绪通道数量。当你调用select返回1时,则代表上次调用select方法到这次调用之间有一个通道变成了就绪状态,然后,再次调用select方法,如果返回值为1,则说明又有一个通道变成了就绪状态。如果你没对第一个就绪通道进行处理,则此时共有两个就绪通道,虽然最后一次select的返回值为1。 - -###selectedKeys() - -当你调用select()方法返回值不为0时,则说明有一个或多个通道已经就绪。你可以通过调用`selector.selectedKeys()`获取就绪的通道: - -```Java -Set selectedKeys = selector.selectedKeys(); -``` - -When you register a channel with a Selector the Channel.register() method returns a SelectionKey object. This key represents that channels registration with that selector. It is these keys you can access via the selectedKeySet() method. From the SelectionKey. - -You can iterate this selected key set to access the ready channels. Here is how that looks: - -```Java -Set selectedKeys = selector.selectedKeys(); - -Iterator keyIterator = selectedKeys.iterator(); - -while(keyIterator.hasNext()) { - - SelectionKey key = keyIterator.next(); - - if(key.isAcceptable()) { - // a connection was accepted by a ServerSocketChannel. - - } else if (key.isConnectable()) { - // a connection was established with a remote server. - - } else if (key.isReadable()) { - // a channel is ready for reading - - } else if (key.isWritable()) { - // a channel is ready for writing - } - - keyIterator.remove(); -} -``` - -This loop iterates the keys in the selected key set. For each key it tests the key to determine what the channel referenced by the key is ready for. - -Notice the `keyIterator.remove()` call at the end of each iteration. The Selector does not remove the SelectionKey instances from the selected key set itself. You have to do this, when you are done processing the channel. The next time the channel becomes "ready" the Selector will add it to the selected key set again. - -The channel returned by the SelectionKey.channel() method should be cast to the channel you need to work with, e.g a ServerSocketChannel or SocketChannel etc. - -###wakeUp() - -A thread that has called the select() method which is blocked, can be made to leave the select() method, even if no channels are yet ready. This is done by having a different thread call the Selector.wakeup() method on the Selector which the first thread has called select() on. The thread waiting inside select() will then return immediately. - -If a different thread calls wakeup() and no thread is currently blocked inside select(), the next thread that calls select() will "wake up" immediately. - -###close() - -When you are finished with the Selector you call its close() method. This closes the Selector and invalidates all SelectionKey instances registered with this Selector. The channels themselves are not closed. - -##Full Selector Example - -Here is a full example which opens a Selector, registers a channel with it (the channel instantiation is left out), and keeps monitoring the Selector for "readiness" of the four events (accept, connect, read, write). - -Selector selector = Selector.open(); - -channel.configureBlocking(false); - -SelectionKey key = channel.register(selector, SelectionKey.OP_READ); - -```Java -while(true) { - - int readyChannels = selector.select(); - - if(readyChannels == 0) continue; - - - Set selectedKeys = selector.selectedKeys(); - - Iterator keyIterator = selectedKeys.iterator(); - - while(keyIterator.hasNext()) { - - SelectionKey key = keyIterator.next(); - - if(key.isAcceptable()) { - // a connection was accepted by a ServerSocketChannel. - - } else if (key.isConnectable()) { - // a connection was established with a remote server. - - } else if (key.isReadable()) { - // a channel is ready for reading - - } else if (key.isWritable()) { - // a channel is ready for writing - } - - keyIterator.remove(); - } -} -``` \ No newline at end of file From 975afaac84bd8247fe62dfa8ffee8434c436eb84 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 10:11:26 +0800 Subject: [PATCH 372/524] Published with https://stackedit.io/ --- ...00\232\351\201\223\347\232\204\344\274\240\350\276\223.md" | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 "Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" diff --git "a/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" "b/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" new file mode 100644 index 0000000..84ce60a --- /dev/null +++ "b/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" @@ -0,0 +1,4 @@ + +##06. Java NIO通道到通道的传输 + +> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file From eb8496f665701300549eb2c4920cbbfd275ee7f9 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 10:21:06 +0800 Subject: [PATCH 373/524] Published with https://stackedit.io/ --- ...23\347\232\204\344\274\240\350\276\223.md" | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git "a/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" "b/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" index 84ce60a..1038f11 100644 --- "a/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" +++ "b/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" @@ -1,4 +1,40 @@ ##06. Java NIO通道到通道的传输 -> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file +In Java NIO you can transfer data directly from one channel to another, if one of the channels is a FileChannel. The FileChannel class has a transferTo() and a transferFrom() method which does this for you. + +##transferFrom() + +The FileChannel.transferFrom() method transfers data from a source channel into the FileChannel. Here is a simple example: + +RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw"); +FileChannel fromChannel = fromFile.getChannel(); + +RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw"); +FileChannel toChannel = toFile.getChannel(); + +long position = 0; +long count = fromChannel.size(); + +toChannel.transferFrom(fromChannel, position, count); +The parameters position and count, tell where in the destination file to start writing (position), and how many bytes to transfer maximally (count). If the source channel has fewer than count bytes, less is transfered. + +Additionally, some SocketChannel implementations may transfer only the data the SocketChannel has ready in its internal buffer here and now - even if the SocketChannel may later have more data available. Thus, it may not transfer the entire data requested (count) from the SocketChannel into FileChannel. + +##transferTo() + +The transferTo() method transfer from a FileChannel into some other channel. Here is a simple example: + +RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw"); +FileChannel fromChannel = fromFile.getChannel(); + +RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw"); +FileChannel toChannel = toFile.getChannel(); + +long position = 0; +long count = fromChannel.size(); + +fromChannel.transferTo(position, count, toChannel); +Notice how similar the example is to the previous. The only real difference is the which FileChannel object the method is called on. The rest is the same. + +The issue with SocketChannel is also present with the transferTo() method. The SocketChannel implementation may only transfer bytes from the FileChannel until the send buffer is full, and then stop. \ No newline at end of file From 04ebf389a8252da543cf0d7d566213da39aba523 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 10:26:11 +0800 Subject: [PATCH 374/524] Published with https://stackedit.io/ --- ...\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" "b/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" index 1038f11..dee6f38 100644 --- "a/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" +++ "b/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" @@ -1,7 +1,7 @@ ##06. Java NIO通道到通道的传输 -In Java NIO you can transfer data directly from one channel to another, if one of the channels is a FileChannel. The FileChannel class has a transferTo() and a transferFrom() method which does this for you. +在Java NIO中,如果其中一个通道是`FileChannel`,那么你可以在两个通道间直接传输数据。`FileChannel`类提供了`transferTo()`和`transferFrom()` 两个方法来在通道中进行数据传输。 ##transferFrom() From 7506db4ce2326aa7d448344e2aad4c3bd2b60727 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 10:40:04 +0800 Subject: [PATCH 375/524] Published with https://stackedit.io/ --- ...51\201\223\347\232\204\344\274\240\350\276\223.md" | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git "a/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" "b/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" index dee6f38..c499cc0 100644 --- "a/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" +++ "b/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" @@ -5,8 +5,9 @@ ##transferFrom() -The FileChannel.transferFrom() method transfers data from a source channel into the FileChannel. Here is a simple example: +`FileChannel.transferFrom()`方法用来将其他通道的数据传输给`FileChannel`。看下这个例子: +```Java RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw"); FileChannel fromChannel = fromFile.getChannel(); @@ -17,9 +18,13 @@ long position = 0; long count = fromChannel.size(); toChannel.transferFrom(fromChannel, position, count); -The parameters position and count, tell where in the destination file to start writing (position), and how many bytes to transfer maximally (count). If the source channel has fewer than count bytes, less is transfered. +``` -Additionally, some SocketChannel implementations may transfer only the data the SocketChannel has ready in its internal buffer here and now - even if the SocketChannel may later have more data available. Thus, it may not transfer the entire data requested (count) from the SocketChannel into FileChannel. +*position* 参数和*count*参数指明目标文件从那个地方开始读取与读取的最大字节数。 + +另外,有一些*SocketChannel*实现也许只是传输当前部分可用数据-即使在传输过程中可能会有更多可用数据,因此`SocketChannel`有可能不会将整个数据都传输给`FileChannel`。 + +(Additionally, some SocketChannel implementations may transfer only the data the SocketChannel has ready in its internal buffer here and now - even if the SocketChannel may later have more data available. Thus, it may not transfer the entire data requested (count) from the SocketChannel into FileChannel.) ##transferTo() From 083d3de61eeeb80c606d8e342d6fb5c789b2cc6a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:04:09 +0800 Subject: [PATCH 376/524] Published with https://stackedit.io/ --- ...232\351\201\223\347\232\204\344\274\240\350\276\223.md" | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git "a/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" "b/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" index c499cc0..f3b96e4 100644 --- "a/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" +++ "b/Java-NIO/06. Java NIO\351\200\232\351\201\223\345\210\260\351\200\232\351\201\223\347\232\204\344\274\240\350\276\223.md" @@ -28,8 +28,9 @@ toChannel.transferFrom(fromChannel, position, count); ##transferTo() -The transferTo() method transfer from a FileChannel into some other channel. Here is a simple example: +`transferTo()`方法将*FileChannel*的数据传输给其他通道。看下这个例子: +```Java RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw"); FileChannel fromChannel = fromFile.getChannel(); @@ -40,6 +41,8 @@ long position = 0; long count = fromChannel.size(); fromChannel.transferTo(position, count, toChannel); -Notice how similar the example is to the previous. The only real difference is the which FileChannel object the method is called on. The rest is the same. +``` + +这个例子跟之前的有点相似,只是*FileChannel*对象调用的方法有所不同,其他都是一样的。 The issue with SocketChannel is also present with the transferTo() method. The SocketChannel implementation may only transfer bytes from the FileChannel until the send buffer is full, and then stop. \ No newline at end of file From a28acef4c3ce3d23aa8d8e13e386b17c70d5ba20 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:06:31 +0800 Subject: [PATCH 377/524] Published with https://stackedit.io/ --- Java-NIO/08.Java NIO FileChannel.md | 82 +++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Java-NIO/08.Java NIO FileChannel.md diff --git a/Java-NIO/08.Java NIO FileChannel.md b/Java-NIO/08.Java NIO FileChannel.md new file mode 100644 index 0000000..76555ea --- /dev/null +++ b/Java-NIO/08.Java NIO FileChannel.md @@ -0,0 +1,82 @@ +#08.Java NIO FileChannel + +A Java NIO FileChannel is a channel that is connected to a file. Using a file channel you can read data from a file, and write data to a file. The Java NIO FileChannel class is NIO's an alternative to reading files with the standard Java IO API. + +A FileChannel cannot be set into non-blocking mode. It always runs in blocking mode. + +Opening a FileChannel + +Before you can use a FileChannel you must open it. You cannot open a FileChannel directly. You need to obtain a FileChannel via an InputStream, OutputStream, or a RandomAccessFile. Here is how you open a FileChannel via a RandomAccessFile: + +RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); +FileChannel inChannel = aFile.getChannel(); + +Reading Data from a FileChannel + +To read data from a FileChannel you call one of the read() methods. Here is an example: + +ByteBuffer buf = ByteBuffer.allocate(48); + +int bytesRead = inChannel.read(buf); +First a Buffer is allocated. The data read from the FileChannel is read into the Buffer. + +Second the FileChannel.read() method is called. This method reads data from the FileChannel into the Buffer. The int returned by the read() method tells how many bytes were witten into the Buffer. If -1 is returned, the end-of-file is reached. + +Writing Data to a FileChannel + +Writing data to a FileChannel is done using the FileChannel.write() method, which takes a Buffer as parameter. Here is an example: + +String newData = "New String to write to file..." + System.currentTimeMillis(); + +ByteBuffer buf = ByteBuffer.allocate(48); +buf.clear(); +buf.put(newData.getBytes()); + +buf.flip(); + +while(buf.hasRemaining()) { + channel.write(buf); +} +Notice how the FileChannel.write() method is called inside a while-loop. There is no guarantee of how many bytes the write() method writes to the FileChannel. Therefore we repeat the write() call until the Buffer has no further bytes to write. + +Closing a FileChannel + +When you are done using a FileChannel you must close it. Here is how that is done: + +channel.close(); +FileChannel Position + +When reading or writing to a FileChannel you do so at a specific position. You can obtain the current position of the FileChannel object by calling the position() method. + +You can also set the position of the FileChannel by calling the position(long pos) method. + +Here are two examples: + +long pos channel.position(); + +channel.position(pos +123); +If you set the position after the end of the file, and try to read from the channel, you will get -1 - the end-of-file marker. + +If you set the position after the end of the file, and write to the channel, the file will be expanded to fit the position and written data. This may result in a "file hole", where the physical file on the disk has gaps in the written data. + +FileChannel Size + +The size() method of the FileChannel object returns the file size of the file the channel is connected to. Here is a simple example: + +long fileSize = channel.size(); +FileChannel Truncate + +You can truncate a file by calling the FileChannel.truncate() method. When you truncate a file, you cut it off at a given length. Here is an example: + +channel.truncate(1024); +This example truncates the file at 1024 bytes in length. + +FileChannel Force + +The FileChannel.force() method flushes all unwritten data from the channel to the disk. An operating system may cache data in memory for performance reasons, so you are not guaranteed that data written to the channel is actually written to disk, until you call the force() method. + +The force() method takes a boolean as parameter, telling whether the file meta data (permission etc.) should be flushed too. + +Here is an example which flushes both data and meta data: + +channel.force(true); \ No newline at end of file From e8430b326630b7d1cf551e5862624c47e2fd0d5f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:09:21 +0800 Subject: [PATCH 378/524] Published with https://stackedit.io/ --- Java-NIO/08.Java NIO FileChannel.md | 37 ++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/Java-NIO/08.Java NIO FileChannel.md b/Java-NIO/08.Java NIO FileChannel.md index 76555ea..618d8bf 100644 --- a/Java-NIO/08.Java NIO FileChannel.md +++ b/Java-NIO/08.Java NIO FileChannel.md @@ -4,28 +4,34 @@ A Java NIO FileChannel is a channel that is connected to a file. Using a file ch A FileChannel cannot be set into non-blocking mode. It always runs in blocking mode. -Opening a FileChannel +##Opening a FileChannel Before you can use a FileChannel you must open it. You cannot open a FileChannel directly. You need to obtain a FileChannel via an InputStream, OutputStream, or a RandomAccessFile. Here is how you open a FileChannel via a RandomAccessFile: +```Java RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); FileChannel inChannel = aFile.getChannel(); +``` -Reading Data from a FileChannel +##Reading Data from a FileChannel To read data from a FileChannel you call one of the read() methods. Here is an example: +```Java ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf); +``` + First a Buffer is allocated. The data read from the FileChannel is read into the Buffer. Second the FileChannel.read() method is called. This method reads data from the FileChannel into the Buffer. The int returned by the read() method tells how many bytes were witten into the Buffer. If -1 is returned, the end-of-file is reached. -Writing Data to a FileChannel +##Writing Data to a FileChannel Writing data to a FileChannel is done using the FileChannel.write() method, which takes a Buffer as parameter. Here is an example: +```Java String newData = "New String to write to file..." + System.currentTimeMillis(); ByteBuffer buf = ByteBuffer.allocate(48); @@ -37,14 +43,19 @@ buf.flip(); while(buf.hasRemaining()) { channel.write(buf); } +``` + Notice how the FileChannel.write() method is called inside a while-loop. There is no guarantee of how many bytes the write() method writes to the FileChannel. Therefore we repeat the write() call until the Buffer has no further bytes to write. -Closing a FileChannel +##Closing a FileChannel When you are done using a FileChannel you must close it. Here is how that is done: +```Java channel.close(); -FileChannel Position +``` + +##FileChannel Position When reading or writing to a FileChannel you do so at a specific position. You can obtain the current position of the FileChannel object by calling the position() method. @@ -52,26 +63,34 @@ You can also set the position of the FileChannel by calling the position(long po Here are two examples: +```Java long pos channel.position(); channel.position(pos +123); +``` + If you set the position after the end of the file, and try to read from the channel, you will get -1 - the end-of-file marker. If you set the position after the end of the file, and write to the channel, the file will be expanded to fit the position and written data. This may result in a "file hole", where the physical file on the disk has gaps in the written data. -FileChannel Size +##FileChannel Size The size() method of the FileChannel object returns the file size of the file the channel is connected to. Here is a simple example: +```Java long fileSize = channel.size(); FileChannel Truncate +``` You can truncate a file by calling the FileChannel.truncate() method. When you truncate a file, you cut it off at a given length. Here is an example: +```Java channel.truncate(1024); +``` + This example truncates the file at 1024 bytes in length. -FileChannel Force +##FileChannel Force The FileChannel.force() method flushes all unwritten data from the channel to the disk. An operating system may cache data in memory for performance reasons, so you are not guaranteed that data written to the channel is actually written to disk, until you call the force() method. @@ -79,4 +98,6 @@ The force() method takes a boolean as parameter, telling whether the file meta d Here is an example which flushes both data and meta data: -channel.force(true); \ No newline at end of file +```Java +channel.force(true); +``` \ No newline at end of file From b83cd78f5da549d648e60b4e9027f4cfde950979 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:16:21 +0800 Subject: [PATCH 379/524] Published with https://stackedit.io/ --- Java-NIO/08.Java NIO FileChannel.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Java-NIO/08.Java NIO FileChannel.md b/Java-NIO/08.Java NIO FileChannel.md index 618d8bf..d129e5f 100644 --- a/Java-NIO/08.Java NIO FileChannel.md +++ b/Java-NIO/08.Java NIO FileChannel.md @@ -1,6 +1,8 @@ #08.Java NIO FileChannel -A Java NIO FileChannel is a channel that is connected to a file. Using a file channel you can read data from a file, and write data to a file. The Java NIO FileChannel class is NIO's an alternative to reading files with the standard Java IO API. +*FileChannel*是一个用于连接文件的通道类。使用*FileChannel*你可以读取文件的数据或往文件里写入数据。使用*FileChannel*可以代替标准的Java IO API中对文件的操作。 + +*FileChannel*不能设置为非阻塞模式,它总是以阻塞模式运行。 A FileChannel cannot be set into non-blocking mode. It always runs in blocking mode. From e7572d2057cc222a3cad56dcb1f18e62dc0f3802 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:18:55 +0800 Subject: [PATCH 380/524] Published with https://stackedit.io/ --- Java-NIO/08.Java NIO FileChannel.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Java-NIO/08.Java NIO FileChannel.md b/Java-NIO/08.Java NIO FileChannel.md index d129e5f..ab23a02 100644 --- a/Java-NIO/08.Java NIO FileChannel.md +++ b/Java-NIO/08.Java NIO FileChannel.md @@ -6,7 +6,7 @@ A FileChannel cannot be set into non-blocking mode. It always runs in blocking mode. -##Opening a FileChannel +##打开FileChannel(Opening a FileChannel) Before you can use a FileChannel you must open it. You cannot open a FileChannel directly. You need to obtain a FileChannel via an InputStream, OutputStream, or a RandomAccessFile. Here is how you open a FileChannel via a RandomAccessFile: @@ -15,7 +15,7 @@ RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); FileChannel inChannel = aFile.getChannel(); ``` -##Reading Data from a FileChannel +##从FileChannel中读取数据(Reading Data from a FileChannel) To read data from a FileChannel you call one of the read() methods. Here is an example: @@ -29,7 +29,7 @@ First a Buffer is allocated. The data read from the FileChannel is read into the Second the FileChannel.read() method is called. This method reads data from the FileChannel into the Buffer. The int returned by the read() method tells how many bytes were witten into the Buffer. If -1 is returned, the end-of-file is reached. -##Writing Data to a FileChannel +##往FileChannel中写入数据(Writing Data to a FileChannel) Writing data to a FileChannel is done using the FileChannel.write() method, which takes a Buffer as parameter. Here is an example: @@ -49,7 +49,7 @@ while(buf.hasRemaining()) { Notice how the FileChannel.write() method is called inside a while-loop. There is no guarantee of how many bytes the write() method writes to the FileChannel. Therefore we repeat the write() call until the Buffer has no further bytes to write. -##Closing a FileChannel +##关闭FileChannel(Closing a FileChannel) When you are done using a FileChannel you must close it. Here is how that is done: From 61be00ea48cd1d22d78f42b141248fc0af217d1f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:22:35 +0800 Subject: [PATCH 381/524] Published with https://stackedit.io/ --- Java-NIO/08.Java NIO FileChannel.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Java-NIO/08.Java NIO FileChannel.md b/Java-NIO/08.Java NIO FileChannel.md index ab23a02..b4200ae 100644 --- a/Java-NIO/08.Java NIO FileChannel.md +++ b/Java-NIO/08.Java NIO FileChannel.md @@ -4,10 +4,10 @@ *FileChannel*不能设置为非阻塞模式,它总是以阻塞模式运行。 -A FileChannel cannot be set into non-blocking mode. It always runs in blocking mode. - ##打开FileChannel(Opening a FileChannel) +当需要使用*FileChannel*时,你需要首先打开一个*FileChannel* + Before you can use a FileChannel you must open it. You cannot open a FileChannel directly. You need to obtain a FileChannel via an InputStream, OutputStream, or a RandomAccessFile. Here is how you open a FileChannel via a RandomAccessFile: ```Java From 0e24b44480f1224553c81313948a4da5402b976f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:29:38 +0800 Subject: [PATCH 382/524] Published with https://stackedit.io/ --- Java-NIO/08.Java NIO FileChannel.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Java-NIO/08.Java NIO FileChannel.md b/Java-NIO/08.Java NIO FileChannel.md index b4200ae..d35a7f6 100644 --- a/Java-NIO/08.Java NIO FileChannel.md +++ b/Java-NIO/08.Java NIO FileChannel.md @@ -6,9 +6,7 @@ ##打开FileChannel(Opening a FileChannel) -当需要使用*FileChannel*时,你需要首先打开一个*FileChannel* - -Before you can use a FileChannel you must open it. You cannot open a FileChannel directly. You need to obtain a FileChannel via an InputStream, OutputStream, or a RandomAccessFile. Here is how you open a FileChannel via a RandomAccessFile: +当需要使用*FileChannel*时,你需要首先打开一个*FileChannel*,但你不能直接打开。你必须要通过*InputStream*,*OutputStream*或*RandomAccessFile*来获得一个*FileChannel*实例。如下面这个例子: ```Java RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); @@ -17,7 +15,7 @@ FileChannel inChannel = aFile.getChannel(); ##从FileChannel中读取数据(Reading Data from a FileChannel) -To read data from a FileChannel you call one of the read() methods. Here is an example: +从*FileChannel*中读取数据,可以调用多个重载的`read()`方法。 ```Java ByteBuffer buf = ByteBuffer.allocate(48); @@ -25,12 +23,14 @@ ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf); ``` -First a Buffer is allocated. The data read from the FileChannel is read into the Buffer. +当**缓冲区(Buffer)**分配之后,数据从*FileChannel*中读取到缓冲区。 -Second the FileChannel.read() method is called. This method reads data from the FileChannel into the Buffer. The int returned by the read() method tells how many bytes were witten into the Buffer. If -1 is returned, the end-of-file is reached. +当`FileChannel.read()`被调用后,这个方法会从*FileChannel*中读取数据到缓冲区。`read()`方法会返回一个int值,这个值代表了写入缓冲区的字节数。如果返回值是-1,则没有数据被读取。 ##往FileChannel中写入数据(Writing Data to a FileChannel) + + Writing data to a FileChannel is done using the FileChannel.write() method, which takes a Buffer as parameter. Here is an example: ```Java From ee30e317509d4ea0e7aa30b84773d7296bba44b6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:31:23 +0800 Subject: [PATCH 383/524] Published with https://stackedit.io/ --- Java-NIO/08.Java NIO FileChannel.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Java-NIO/08.Java NIO FileChannel.md b/Java-NIO/08.Java NIO FileChannel.md index d35a7f6..ccb09fa 100644 --- a/Java-NIO/08.Java NIO FileChannel.md +++ b/Java-NIO/08.Java NIO FileChannel.md @@ -29,9 +29,7 @@ int bytesRead = inChannel.read(buf); ##往FileChannel中写入数据(Writing Data to a FileChannel) - - -Writing data to a FileChannel is done using the FileChannel.write() method, which takes a Buffer as parameter. Here is an example: +往*FileChannel*中写数据用的是`FileChannel.write()`方法,这个方法也会带有个Buffer类型参数。 ```Java String newData = "New String to write to file..." + System.currentTimeMillis(); From 2c8570ac7e9184251aae574c7a6b6fe7c2fc7942 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:34:22 +0800 Subject: [PATCH 384/524] Published with https://stackedit.io/ --- Java-NIO/08.Java NIO FileChannel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Java-NIO/08.Java NIO FileChannel.md b/Java-NIO/08.Java NIO FileChannel.md index ccb09fa..b3c02f6 100644 --- a/Java-NIO/08.Java NIO FileChannel.md +++ b/Java-NIO/08.Java NIO FileChannel.md @@ -45,7 +45,7 @@ while(buf.hasRemaining()) { } ``` -Notice how the FileChannel.write() method is called inside a while-loop. There is no guarantee of how many bytes the write() method writes to the FileChannel. Therefore we repeat the write() call until the Buffer has no further bytes to write. + 注意这里的`FileChannel.write()`方法是在while循环里面进行的。我们并不知道有多少数据要写入到*FileChannel*中,因此我们需要重复地调用`write()`方法直到缓冲区中没有数据可写。 ##关闭FileChannel(Closing a FileChannel) From 458dcea91bca9fe0f410cba7cd1f42145bdb9b5a Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:51:16 +0800 Subject: [PATCH 385/524] Published with https://stackedit.io/ --- Java-NIO/08.Java NIO FileChannel.md | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Java-NIO/08.Java NIO FileChannel.md b/Java-NIO/08.Java NIO FileChannel.md index b3c02f6..19c14a8 100644 --- a/Java-NIO/08.Java NIO FileChannel.md +++ b/Java-NIO/08.Java NIO FileChannel.md @@ -49,7 +49,8 @@ while(buf.hasRemaining()) { ##关闭FileChannel(Closing a FileChannel) -When you are done using a FileChannel you must close it. Here is how that is done: +当使用完FileChannel后,必须要关闭它: + ```Java channel.close(); @@ -57,11 +58,9 @@ channel.close(); ##FileChannel Position -When reading or writing to a FileChannel you do so at a specific position. You can obtain the current position of the FileChannel object by calling the position() method. - -You can also set the position of the FileChannel by calling the position(long pos) method. +当从*FileChannel*读取数据往其中写人数据时,我们需要要指定特定的位置。你可以通过调用`position()`方法来获得*FileChannel*当前的位置。 -Here are two examples: +你也可以通过`position(long pos)`方法来设置*FileChannel*的位置。 ```Java long pos channel.position(); @@ -69,34 +68,33 @@ long pos channel.position(); channel.position(pos +123); ``` -If you set the position after the end of the file, and try to read from the channel, you will get -1 - the end-of-file marker. +如果你将*position*设置到文件的末尾之后,当你再对*FileChannel*进行读取时,将会返回-1,表明读取到了文件末尾。 + +如果你将*position*设置到文件的末尾之后,让你往*FileChannel*写入数据时,文件就会自动拓展到`position`所指定的位置并写入数据。这会导致**文件空洞(File Hole)**。 -If you set the position after the end of the file, and write to the channel, the file will be expanded to fit the position and written data. This may result in a "file hole", where the physical file on the disk has gaps in the written data. ##FileChannel Size -The size() method of the FileChannel object returns the file size of the file the channel is connected to. Here is a simple example: +`FileChannel.size()`方法会返回通道所连接的文件的大小。 ```Java long fileSize = channel.size(); -FileChannel Truncate ``` -You can truncate a file by calling the FileChannel.truncate() method. When you truncate a file, you cut it off at a given length. Here is an example: +##FileChannel Truncate + +你可以通过`FileChannel.truncate()`方法对通道所关联的文件进行截取: ```Java channel.truncate(1024); ``` -This example truncates the file at 1024 bytes in length. ##FileChannel Force -The FileChannel.force() method flushes all unwritten data from the channel to the disk. An operating system may cache data in memory for performance reasons, so you are not guaranteed that data written to the channel is actually written to disk, until you call the force() method. - -The force() method takes a boolean as parameter, telling whether the file meta data (permission etc.) should be flushed too. +`FileChannel.force()`方法会将所有通道中的数据刷新到磁盘中。操作系统会处于性能考虑将数据缓存到内存中,所以你不能保证写入到通道中的数据会立刻同步到磁盘,因此你可以通过`force()`方法将通道中的数据刷新到物理磁盘。 -Here is an example which flushes both data and meta data: +`FileChannel.forece()`方法带有一个布尔类型的参数,这个参数用于指定文件的**元数据(meta data)**是否也需要刷新到物理磁盘。 ```Java channel.force(true); From 34fa95c833bc4485f669321701feca0d6a1b8178 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:54:30 +0800 Subject: [PATCH 386/524] Published with https://stackedit.io/ --- Java-NIO/09.Java NIO SocketChannel.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Java-NIO/09.Java NIO SocketChannel.md diff --git a/Java-NIO/09.Java NIO SocketChannel.md b/Java-NIO/09.Java NIO SocketChannel.md new file mode 100644 index 0000000..8197c33 --- /dev/null +++ b/Java-NIO/09.Java NIO SocketChannel.md @@ -0,0 +1,3 @@ +#09.Java NIO SocketChannel + +> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file From 29b1236ee74252ff514dd4c474dc99eb0b833bce Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:55:51 +0800 Subject: [PATCH 387/524] Published with https://stackedit.io/ --- Java-NIO/09.Java NIO SocketChannel.md | 86 ++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/Java-NIO/09.Java NIO SocketChannel.md b/Java-NIO/09.Java NIO SocketChannel.md index 8197c33..9b6c223 100644 --- a/Java-NIO/09.Java NIO SocketChannel.md +++ b/Java-NIO/09.Java NIO SocketChannel.md @@ -1,3 +1,87 @@ #09.Java NIO SocketChannel -> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file +A Java NIO SocketChannel is a channel that is connected to a TCP network socket. It is Java NIO's equivalent of Java Networking's Sockets. There are two ways a SocketChannel can be created: + +You open a SocketChannel and connect to a server somewhere on the internet. +A SocketChannel can be created when an incoming connection arrives at a ServerSocketChannel. + + +##Opening a SocketChannel + +Here is how you open a SocketChannel: + +```Java +SocketChannel socketChannel = SocketChannel.open(); +socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80)); +``` + +##Closing a SocketChannel + +You close a SocketChannel after use by calling the SocketChannel.close() method. Here is how that is done: + +```Java +socketChannel.close(); +``` + +##Reading from a SocketChannel + +To read data from a SocketChannel you call one of the read() methods. Here is an example: + +```Java +ByteBuffer buf = ByteBuffer.allocate(48); + +int bytesRead = socketChannel.read(buf); +``` + +First a Buffer is allocated. The data read from the SocketChannel is read into the Buffer. + +Second the SocketChannel.read() method is called. This method reads data from the SocketChannel into the Buffer. The int returned by the read() method tells how many bytes were witten into the Buffer. If -1 is returned, the end-of-stream is reached (the connection is closed). + +##Writing to a SocketChannel + +Writing data to a SocketChannel is done using the SocketChannel.write() method, which takes a Buffer as parameter. Here is an example: + +```Java +String newData = "New String to write to file..." + System.currentTimeMillis(); + +ByteBuffer buf = ByteBuffer.allocate(48); +buf.clear(); +buf.put(newData.getBytes()); + +buf.flip(); + +while(buf.hasRemaining()) { + channel.write(buf); +} +``` + +Notice how the SocketChannel.write() method is called inside a while-loop. There is no guarantee of how many bytes the write() method writes to the SocketChannel. Therefore we repeat the write() call until the Buffer has no further bytes to write. + +##Non-blocking Mode + +You can set a SocketChannel into non-blocking mode. When you do so, you can call connect(), read() and write() in asynchronous mode. + +##connect() + +If the SocketChannel is in non-blocking mode, and you call connect(), the method may return before a connection is established. To determine whether the connection is established, you can call the finishConnect() method, like this: + +```Java +socketChannel.configureBlocking(false); +socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80)); + +while(! socketChannel.finishConnect() ){ + //wait, or do something else... +} +``` + +##write() + +In non-blocking mode the write() method may return without having written anything. Therefore you need to call the write() method in a loop. But, since this is already being done in the previous write examples, no need to do anything differently here. + +##read() + +In non-blocking mode the read() method may return without having read any data at all. Therefore you need to pay attention to the returned int, which tells how many bytes were read. + +##Non-blocking Mode with Selectors + +The non-blocking mode of SocketChannel's works much better with Selector's. By registering one or more SocketChannel's with a Selector, you can ask the Selector for channels that are ready for reading, writing etc. How to use Selector's with SocketChannel's is explained in more detail in a later text in this tutorial. \ No newline at end of file From a271c4a11ef61b7337dc39d019c55558bc751402 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 11:59:26 +0800 Subject: [PATCH 388/524] Published with https://stackedit.io/ --- Java-NIO/10.Java NIO ServerSocketChannel.md | 73 +++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Java-NIO/10.Java NIO ServerSocketChannel.md diff --git a/Java-NIO/10.Java NIO ServerSocketChannel.md b/Java-NIO/10.Java NIO ServerSocketChannel.md new file mode 100644 index 0000000..9f1cff7 --- /dev/null +++ b/Java-NIO/10.Java NIO ServerSocketChannel.md @@ -0,0 +1,73 @@ + +#10.Java NIO ServerSocketChannel + +A Java NIO ServerSocketChannel is a channel that can listen for incoming TCP connections, just like a ServerSocket in standard Java Networking. The ServerSocketChannel class is located in the java.nio.channels package. + +Here is an example: + +```Java +ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); + +serverSocketChannel.socket().bind(new InetSocketAddress(9999)); + +while(true){ + SocketChannel socketChannel = + serverSocketChannel.accept(); + + //do something with socketChannel... +} +``` + +##Opening a ServerSocketChannel + +You open a ServerSocketChannel by calling the ServerSocketChannel.open() method. Here is how that looks: + +```Java +ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); +``` + + +##Closing a ServerSocketChannel + +Closing a ServerSocketChannel is done by calling the ServerSocketChannel.close() method. Here is how that looks: + +```Java +serverSocketChannel.close(); +``` + +##Listening for Incoming Connections + +Listening for incoming connections is done by calling the ServerSocketChannel.accept() method. When the accept() method returns, it returns a SocketChannel with an incoming connection. Thus, the accept() method blocks until an incoming connection arrives. + +Since you are typically not interested in listening just for a single connection, you call the accept() inside a while-loop. Here is how that looks: + +```Java +while(true){ + SocketChannel socketChannel = + serverSocketChannel.accept(); + + //do something with socketChannel... +} +``` + +Of course you would use some other stop-criteria than true inside the while-loop. + +##Non-blocking Mode + +A ServerSocketChannel can be set into non-blocking mode. In non-blocking mode the accept() method returns immediately, and may thus return null, if no incoming connection had arrived. Therefore you will have to check if the returned SocketChannel is null. Here is an example: + +```Java +ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); + +serverSocketChannel.socket().bind(new InetSocketAddress(9999)); +serverSocketChannel.configureBlocking(false); + +while(true){ + SocketChannel socketChannel = + serverSocketChannel.accept(); + + if(socketChannel != null){ + //do something with socketChannel... + } +} +``` From d86a2dd1783309910338e298b937d79ff5eee338 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 12:15:06 +0800 Subject: [PATCH 389/524] Published with https://stackedit.io/ --- Java-NIO/11.Java NIO DatagramChannel.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Java-NIO/11.Java NIO DatagramChannel.md diff --git a/Java-NIO/11.Java NIO DatagramChannel.md b/Java-NIO/11.Java NIO DatagramChannel.md new file mode 100644 index 0000000..a06101c --- /dev/null +++ b/Java-NIO/11.Java NIO DatagramChannel.md @@ -0,0 +1 @@ +#11.Java NIO DatagramChannel \ No newline at end of file From ae6fd2b18506a4acbcbdc0c618d0356697b80c02 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 12:15:20 +0800 Subject: [PATCH 390/524] Published with https://stackedit.io/ --- Java-NIO/11.Java NIO DatagramChannel.md | 49 ++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/Java-NIO/11.Java NIO DatagramChannel.md b/Java-NIO/11.Java NIO DatagramChannel.md index a06101c..ef9ecdd 100644 --- a/Java-NIO/11.Java NIO DatagramChannel.md +++ b/Java-NIO/11.Java NIO DatagramChannel.md @@ -1 +1,48 @@ -#11.Java NIO DatagramChannel \ No newline at end of file +#11.Java NIO DatagramChannel + +A Java NIO DatagramChannel is a channel that can send and receive UDP packets. Since UDP is a connection-less network protocol, you cannot just by default read and write to a DatagramChannel like you do from other channels. Instead you send and receive packets of data. + +Opening a DatagramChannel + +Here is how you open a DatagramChannel: + +DatagramChannel channel = DatagramChannel.open(); +channel.socket().bind(new InetSocketAddress(9999)); +This example opens a DatagramChannel which can receive packets on UDP port 9999. + +Receiving Data + +You receive data from a DatagramChannel by calling its receive() method, like this: + +ByteBuffer buf = ByteBuffer.allocate(48); +buf.clear(); + +channel.receive(buf); +The receive() method will copy the content of a received packet of data into the given Buffer. If the received packet contains more data than the Buffer can contain, the remaining data is discarded silently. + +Sending Data + +You can send data via a DatagramChannel by calling its send() method, like this: + +String newData = "New String to write to file..." + + System.currentTimeMillis(); + +ByteBuffer buf = ByteBuffer.allocate(48); +buf.clear(); +buf.put(newData.getBytes()); +buf.flip(); + +int bytesSent = channel.send(buf, new InetSocketAddress("jenkov.com", 80)); +This example sends the string to the "jenkov.com" server on UDP port 80. Nothing is listening on that port though, so nothing will happen. You will not be notified of whether the send packet was received or not, since UDP does not make any guarantees about delivery of data. + +Connecting to a Specific Address + +It is possible to "connect" a DatagramChannel to a specific address on the network. Since UDP is connection-less, this way of connecting to an address does not create a real connection, like with a TCP channel. Rather, it locks your DatagramChannel so you can only send and receive data packets from one specific address. + +Here is an example: + +channel.connect(new InetSocketAddress("jenkov.com", 80)); +When connected you can also use the read() and write() method, as if you were using a traditional channel. You just don't have any guarantees about delivery of the sent data. Here are a few examples: + +int bytesRead = channel.read(buf); +int bytesWritten = channel.write(buf); \ No newline at end of file From 24bd3694916e9c5b4031c06787f7c55638d1fca2 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 12:16:31 +0800 Subject: [PATCH 391/524] Published with https://stackedit.io/ --- Java-NIO/12.Java NIO Pipe.md | 44 ++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Java-NIO/12.Java NIO Pipe.md diff --git a/Java-NIO/12.Java NIO Pipe.md b/Java-NIO/12.Java NIO Pipe.md new file mode 100644 index 0000000..426e0b0 --- /dev/null +++ b/Java-NIO/12.Java NIO Pipe.md @@ -0,0 +1,44 @@ +#12.Java NIO Pipe + +A Java NIO Pipe is a one-way data connection between two threads. A Pipe has a source channel and a sink channel. You write data to the sink channel. This data can then be read from the source channel. + +Here is an illustration of the Pipe principle: + +Java NIO: Pipe Internals +Java NIO: Pipe Internals +Creating a Pipe + +You open a Pipe by calling the Pipe.open() method. Here is how that looks: + +Pipe pipe = Pipe.open(); +Writing to a Pipe + +To write to a Pipe you need to access the sink channel. Here is how that is done: + +Pipe.SinkChannel sinkChannel = pipe.sink(); +You write to a SinkChannel by calling it's write() method, like this: + +String newData = "New String to write to file..." + System.currentTimeMillis(); + +ByteBuffer buf = ByteBuffer.allocate(48); +buf.clear(); +buf.put(newData.getBytes()); + +buf.flip(); + +while(buf.hasRemaining()) { + sinkChannel.write(buf); +} +Reading from a Pipe + +To read from a Pipe you need to access the source channel. Here is how that is done: + +Pipe.SourceChannel sourceChannel = pipe.source(); +To read from the source channel you call its read() method like this: + +ByteBuffer buf = ByteBuffer.allocate(48); + +int bytesRead = inChannel.read(buf); +The int returned by the read() method tells how many bytes were read into the buffer. + + \ No newline at end of file From 54128e1deeb7ab588c639cf7f70fe0ccae1e6f0b Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 12:17:20 +0800 Subject: [PATCH 392/524] Published with https://stackedit.io/ --- Java-NIO/13.Java NIO vs IO.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Java-NIO/13.Java NIO vs IO.md diff --git a/Java-NIO/13.Java NIO vs IO.md b/Java-NIO/13.Java NIO vs IO.md new file mode 100644 index 0000000..1003ccf --- /dev/null +++ b/Java-NIO/13.Java NIO vs IO.md @@ -0,0 +1 @@ +#13.Java NIO vs. IO \ No newline at end of file From f262523e6e3e2b8a4f604d7042763c8b23b771db Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 12:17:51 +0800 Subject: [PATCH 393/524] Published with https://stackedit.io/ --- Java-NIO/13.Java NIO vs IO.md | 116 +++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/Java-NIO/13.Java NIO vs IO.md b/Java-NIO/13.Java NIO vs IO.md index 1003ccf..5b1b9ef 100644 --- a/Java-NIO/13.Java NIO vs IO.md +++ b/Java-NIO/13.Java NIO vs IO.md @@ -1 +1,115 @@ -#13.Java NIO vs. IO \ No newline at end of file +#13.Java NIO vs. IO + +When studying both the Java NIO and IO API's, a question quickly pops into mind: + +When should I use IO and when should I use NIO? + +In this text I will try to shed some light on the differences between Java NIO and IO, their use cases, and how they affect the design of your code. + +Main Differences Betwen Java NIO and IO + +The table below summarizes the main differences between Java NIO and IO. I will get into more detail about each difference in the sections following the table. + +IO NIO +Stream oriented Buffer oriented +Blocking IO Non blocking IO + Selectors +Stream Oriented vs. Buffer Oriented + +The first big difference between Java NIO and IO is that IO is stream oriented, where NIO is buffer oriented. So, what does that mean? + +Java IO being stream oriented means that you read one or more bytes at a time, from a stream. What you do with the read bytes is up to you. They are not cached anywhere. Furthermore, you cannot move forth and back in the data in a stream. If you need to move forth and back in the data read from a stream, you will need to cache it in a buffer first. + +Java NIO's buffer oriented approach is slightly different. Data is read into a buffer from which it is later processed. You can move forth and back in the buffer as you need to. This gives you a bit more flexibility during processing. However, you also need to check if the buffer contains all the data you need in order to fully process it. And, you need to make sure that when reading more data into the buffer, you do not overwrite data in the buffer you have not yet processed. + +Blocking vs. Non-blocking IO + +Java IO's various streams are blocking. That means, that when a thread invokes a read() or write(), that thread is blocked until there is some data to read, or the data is fully written. The thread can do nothing else in the meantime. + +Java NIO's non-blocking mode enables a thread to request reading data from a channel, and only get what is currently available, or nothing at all, if no data is currently available. Rather than remain blocked until data becomes available for reading, the thread can go on with something else. + +The same is true for non-blocking writing. A thread can request that some data be written to a channel, but not wait for it to be fully written. The thread can then go on and do something else in the mean time. + +What threads spend their idle time on when not blocked in IO calls, is usually performing IO on other channels in the meantime. That is, a single thread can now manage multiple channels of input and output. + +Selectors + +Java NIO's selectors allow a single thread to monitor multiple channels of input. You can register multiple channels with a selector, then use a single thread to "select" the channels that have input available for processing, or select the channels that are ready for writing. This selector mechanism makes it easy for a single thread to manage multiple channels. + +How NIO and IO Influences Application Design + +Whether you choose NIO or IO as your IO toolkit may impact the following aspects of your application design: + +The API calls to the NIO or IO classes. +The processing of data. +The number of thread used to process the data. +The API Calls + +Of course the API calls when using NIO look different than when using IO. This is no surprise. Rather than just read the data byte for byte from e.g. an InputStream, the data must first be read into a buffer, and then be processed from there. + +The Processing of Data + +The processing of the data is also affected when using a pure NIO design, vs. an IO design. + +In an IO design you read the data byte for byte from an InputStream or a Reader. Imagine you were processing a stream of line based textual data. For instance: + +Name: Anna +Age: 25 +Email: anna@mailserver.com +Phone: 1234567890 +This stream of text lines could be processed like this: + +InputStream input = ... ; // get the InputStream from the client socket + +BufferedReader reader = new BufferedReader(new InputStreamReader(input)); + +String nameLine = reader.readLine(); +String ageLine = reader.readLine(); +String emailLine = reader.readLine(); +String phoneLine = reader.readLine(); +Notice how the processing state is determined by how far the program has executed. In other words, once the first reader.readLine() method returns, you know for sure that a full line of text has been read. The readLine() blocks until a full line is read, that's why. You also know that this line contains the name. Similarly, when the second readLine() call returns, you know that this line contains the age etc. + +As you can see, the program progresses only when there is new data to read, and for each step you know what that data is. Once the executing thread have progressed past reading a certain piece of data in the code, the thread is not going backwards in the data (mostly not). This principle is also illustrated in this diagram: + +Java IO: Reading data from a blocking stream. +Java IO: Reading data from a blocking stream. +A NIO implementation would look different. Here is a simplified example: + +ByteBuffer buffer = ByteBuffer.allocate(48); + +int bytesRead = inChannel.read(buffer); +Notice the second line which reads bytes from the channel into the ByteBuffer. When that method call returns you don't know if all the data you need is inside the buffer. All you know is that the buffer contains some bytes. This makes processing somewhat harder. + +Imagine if, after the first read(buffer) call, that all what was read into the buffer was half a line. For instance, "Name: An". Can you process that data? Not really. You need to wait until at leas a full line of data has been into the buffer, before it makes sense to process any of the data at all. + +So how do you know if the buffer contains enough data for it to make sense to be processed? Well, you don't. The only way to find out, is to look at the data in the buffer. The result is, that you may have to inspect the data in the buffer several times before you know if all the data is inthere. This is both inefficient, and can become messy in terms of program design. For instance: + +ByteBuffer buffer = ByteBuffer.allocate(48); + +int bytesRead = inChannel.read(buffer); + +while(! bufferFull(bytesRead) ) { + bytesRead = inChannel.read(buffer); +} +The bufferFull() method has to keep track of how much data is read into the buffer, and return either true or false, depending on whether the buffer is full. In other words, if the buffer is ready for processing, it is considered full. + +The bufferFull() method scans through the buffer, but must leave the buffer in the same state as before the bufferFull() method was called. If not, the next data read into the buffer might not be read in at the correct location. This is not impossible, but it is yet another issue to watch out for. + +If the buffer is full, it can be processed. If it is not full, you might be able to partially process whatever data is there, if that makes sense in your particular case. In many cases it doesn't. + +The is-data-in-buffer-ready loop is illustrated in this diagram: + +Java NIO: Reading data from a channel until all needed data is in buffer. +Java NIO: Reading data from a channel until all needed data is in buffer. +Summary + +NIO allows you to manage multiple channels (network connections or files) using only a single (or few) threads, but the cost is that parsing the data might be somewhat more complicated than when reading data from a blocking stream. + +If you need to manage thousands of open connections simultanously, which each only send a little data, for instance a chat server, implementing the server in NIO is probably an advantage. Similarly, if you need to keep a lot of open connections to other computers, e.g. in a P2P network, using a single thread to manage all of your outbound connections might be an advantage. This one thread, multiple connections design is illustrated in this diagram: + +Java NIO: A single thread managing multiple connections. +Java NIO: A single thread managing multiple connections. +If you have fewer connections with very high bandwidth, sending a lot of data at a time, perhaps a classic IO server implementation might be the best fit. This diagram illustrates a classic IO server design: + +Java IO: A classic IO server design - one connection handled by one thread. +Java IO: A classic IO server design - one connection handled by one thread. From 3ab93a02e7ce19628906694a5c8d4cfaac05f3f3 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 16:15:46 +0800 Subject: [PATCH 394/524] Published with https://stackedit.io/ --- ...21\345\267\245\345\205\267\347\261\273.md" | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 "Java-Concurrency-Util/01.Java\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273.md" diff --git "a/Java-Concurrency-Util/01.Java\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273.md" "b/Java-Concurrency-Util/01.Java\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273.md" new file mode 100644 index 0000000..7451b9e --- /dev/null +++ "b/Java-Concurrency-Util/01.Java\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273.md" @@ -0,0 +1,23 @@ +#01.Java并发工具类 + +Java 5 added a new Java package to the Java platform, the java.util.concurrent package. This package contains a set of classes that makes it easier to develop concurrent (multithreaded) applications in Java. Before this package was added, you would have to program your utility classes yourself. + +In this tutorial I will take you through the new java.util.concurrent classes, one by one, so you can learn how to use them. I will use the versions in Java 6. I am not sure if there are any differences to the Java 5 versions. + +I will not explain the core issues of concurrency in Java - the theory behind it, that is. If you are interested in that, check out my Java Concurrency tutorial. + + +Work in Progress + +This tutorial is very much "work in progress", so if you spot a missing class or interface, please be patient. I will add it when I get the time to do it. + + +Table of Contents + +Here is a list of the topics covered in this java.util.concurrent trail. This list (menu) is also present at the top right of every page in the trail. + + +Feel Free to Contact Me + +If you disagree with anything I write here about the java.util.concurrent utilities, or just have comments, questions, etc, feel free to send me an email. You wouldn't be the first to do so. You can find my email address on the about page. + From 016cb60f195c480ce01f7aca40a401f43ba675fc Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 16:17:11 +0800 Subject: [PATCH 395/524] Published with https://stackedit.io/ --- ...\266\345\217\221\345\267\245\345\205\267\347\261\273.md" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git "a/Java-Concurrency-Util/01.Java\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273.md" "b/Java-Concurrency-Util/01.Java\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273.md" index 7451b9e..191a794 100644 --- "a/Java-Concurrency-Util/01.Java\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273.md" +++ "b/Java-Concurrency-Util/01.Java\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273.md" @@ -7,17 +7,17 @@ In this tutorial I will take you through the new java.util.concurrent classes, o I will not explain the core issues of concurrency in Java - the theory behind it, that is. If you are interested in that, check out my Java Concurrency tutorial. -Work in Progress +##Work in Progress This tutorial is very much "work in progress", so if you spot a missing class or interface, please be patient. I will add it when I get the time to do it. -Table of Contents +##Table of Contents Here is a list of the topics covered in this java.util.concurrent trail. This list (menu) is also present at the top right of every page in the trail. -Feel Free to Contact Me +##Feel Free to Contact Me If you disagree with anything I write here about the java.util.concurrent utilities, or just have comments, questions, etc, feel free to send me an email. You wouldn't be the first to do so. You can find my email address on the about page. From 0608f53cf36961d015adefa51180a58e4be45222 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 16:17:44 +0800 Subject: [PATCH 396/524] Create README.md --- Java-Concurrency-Util/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Java-Concurrency-Util/README.md diff --git a/Java-Concurrency-Util/README.md b/Java-Concurrency-Util/README.md new file mode 100644 index 0000000..d1d2694 --- /dev/null +++ b/Java-Concurrency-Util/README.md @@ -0,0 +1 @@ +翻译自:http://tutorials.jenkov.com/java-util-concurrent/index.html From 6ce50dccd3f180a1e7d8ba3001faff0293dd6661 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 16:24:35 +0800 Subject: [PATCH 397/524] Published with https://stackedit.io/ --- ...7\357\274\210BlockingQueue\357\274\211.md" | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 "Java-Concurrency-Util /02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" diff --git "a/Java-Concurrency-Util /02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util /02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" new file mode 100644 index 0000000..39fa489 --- /dev/null +++ "b/Java-Concurrency-Util /02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -0,0 +1,113 @@ +#02.阻塞队列(BlockingQueue) + +The Java BlockingQueue interface in the java.util.concurrent class represents a queue which is thread safe to put into, and take instances from. In this text I will show you how to use this BlockingQueue. + +This text will not discuss how to implement a BlockingQueue in Java yourself. If you are interested in that, I have a text on Blocking Queues in my more theoretical Java Concurrency Tutorial. + +##BlockingQueue Usage + +A BlockingQueue is typically used to have on thread produce objects, which another thread consumes. Here is a diagram that illustrates this principle: + +A BlockingQueue with one thread putting into it, and another thread taking from it. +A BlockingQueue with one thread putting into it, and another thread taking from it. +The producing thread will keep producing new objects and insert them into the queue, until the queue reaches some upper bound on what it can contain. It's limit, in other words. If the blocking queue reaches its upper limit, the producing thread is blocked while trying to insert the new object. It remains blocked until a consuming thread takes an object out of the queue. + +The consuming thread keeps taking objects out of the blocking queue, and processes them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue. + + +##BlockingQueue Methods + +A BlockingQueue has 4 different sets of methods for inserting, removing and examining the elements in the queue. Each set of methods behaves differently in case the requested operation cannot be carried out immediately. Here is a table of the methods: + + Throws Exception Special Value Blocks Times Out +Insert add(o) offer(o) put(o) offer(o, timeout, timeunit) +Remove remove(o) poll(o) take(o) poll(timeout, timeunit) +Examine element(o) peek(o) +The 4 different sets of behaviour means this: + +Throws Exception: +If the attempted operation is not possible immediately, an exception is thrown. +Special Value: +If the attempted operation is not possible immediately, a special value is returned (often true / false). +Blocks: +If the attempted operation is not possible immedidately, the method call blocks until it is. +Times Out: +If the attempted operation is not possible immedidately, the method call blocks until it is, but waits no longer than the given timeout. Returns a special value telling whether the operation succeeded or not (typically true / false). +It is not possible to insert null into a BlockingQueue. If you try to insert null, the BlockingQueue will throw a NullPointerException. + +It is also possible to access all the elements inside a BlockingQueue, and not just the elements at the start and end. For instance, say you have queued an object for processing, but your application decides to cancel it. You can then call e.g. remove(o) to remove a specific object in the queue. However, this is not done very efficiently, so you should not use these Collection methods unless you really have to. + +##BlockingQueue Implementations + +Since BlockingQueue is an interface, you need to use one of its implementations to use it. The java.util.concurrent package has the following implementations of the BlockingQueue interface (in Java 6): + +ArrayBlockingQueue +DelayQueue +LinkedBlockingQueue +PriorityBlockingQueue +SynchronousQueue +Click the links in the list to read more about each implementation. If a link cannot be clicked, that implementation has not yet been described. Check back again in the future, or check out the JavaDoc's for more detail. + +##Java BlockingQueue Example + +Here is a Java BlockingQueue example. The example uses the ArrayBlockingQueue implementation of the BlockingQueue interface. + +First, the BlockingQueueExample class which starts a Producer and a Consumer in separate threads. The Producer inserts strings into a shared BlockingQueue, and the Consumer takes them out. + +public class BlockingQueueExample { + + public static void main(String[] args) throws Exception { + + BlockingQueue queue = new ArrayBlockingQueue(1024); + + Producer producer = new Producer(queue); + Consumer consumer = new Consumer(queue); + + new Thread(producer).start(); + new Thread(consumer).start(); + + Thread.sleep(4000); + } +} +Here is the Producer class. Notice how it sleeps a second between each put() call. This will cause the Consumer to block, while waiting for objects in the queue. + +public class Producer implements Runnable{ + + protected BlockingQueue queue = null; + + public Producer(BlockingQueue queue) { + this.queue = queue; + } + + public void run() { + try { + queue.put("1"); + Thread.sleep(1000); + queue.put("2"); + Thread.sleep(1000); + queue.put("3"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} +Here is the Consumer class. It just takes out the objects from the queue, and prints them to System.out. + +public class Consumer implements Runnable{ + + protected BlockingQueue queue = null; + + public Consumer(BlockingQueue queue) { + this.queue = queue; + } + + public void run() { + try { + System.out.println(queue.take()); + System.out.println(queue.take()); + System.out.println(queue.take()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file From 7b994e594ca4efd439501ee6a238f618610b93ce Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 16:26:01 +0800 Subject: [PATCH 398/524] =?UTF-8?q?Delete=2002.=E9=98=BB=E5=A1=9E=E9=98=9F?= =?UTF-8?q?=E5=88=97=EF=BC=88BlockingQueue=EF=BC=89.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...7\357\274\210BlockingQueue\357\274\211.md" | 113 ------------------ 1 file changed, 113 deletions(-) delete mode 100644 "Java-Concurrency-Util /02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" diff --git "a/Java-Concurrency-Util /02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util /02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" deleted file mode 100644 index 39fa489..0000000 --- "a/Java-Concurrency-Util /02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ /dev/null @@ -1,113 +0,0 @@ -#02.阻塞队列(BlockingQueue) - -The Java BlockingQueue interface in the java.util.concurrent class represents a queue which is thread safe to put into, and take instances from. In this text I will show you how to use this BlockingQueue. - -This text will not discuss how to implement a BlockingQueue in Java yourself. If you are interested in that, I have a text on Blocking Queues in my more theoretical Java Concurrency Tutorial. - -##BlockingQueue Usage - -A BlockingQueue is typically used to have on thread produce objects, which another thread consumes. Here is a diagram that illustrates this principle: - -A BlockingQueue with one thread putting into it, and another thread taking from it. -A BlockingQueue with one thread putting into it, and another thread taking from it. -The producing thread will keep producing new objects and insert them into the queue, until the queue reaches some upper bound on what it can contain. It's limit, in other words. If the blocking queue reaches its upper limit, the producing thread is blocked while trying to insert the new object. It remains blocked until a consuming thread takes an object out of the queue. - -The consuming thread keeps taking objects out of the blocking queue, and processes them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue. - - -##BlockingQueue Methods - -A BlockingQueue has 4 different sets of methods for inserting, removing and examining the elements in the queue. Each set of methods behaves differently in case the requested operation cannot be carried out immediately. Here is a table of the methods: - - Throws Exception Special Value Blocks Times Out -Insert add(o) offer(o) put(o) offer(o, timeout, timeunit) -Remove remove(o) poll(o) take(o) poll(timeout, timeunit) -Examine element(o) peek(o) -The 4 different sets of behaviour means this: - -Throws Exception: -If the attempted operation is not possible immediately, an exception is thrown. -Special Value: -If the attempted operation is not possible immediately, a special value is returned (often true / false). -Blocks: -If the attempted operation is not possible immedidately, the method call blocks until it is. -Times Out: -If the attempted operation is not possible immedidately, the method call blocks until it is, but waits no longer than the given timeout. Returns a special value telling whether the operation succeeded or not (typically true / false). -It is not possible to insert null into a BlockingQueue. If you try to insert null, the BlockingQueue will throw a NullPointerException. - -It is also possible to access all the elements inside a BlockingQueue, and not just the elements at the start and end. For instance, say you have queued an object for processing, but your application decides to cancel it. You can then call e.g. remove(o) to remove a specific object in the queue. However, this is not done very efficiently, so you should not use these Collection methods unless you really have to. - -##BlockingQueue Implementations - -Since BlockingQueue is an interface, you need to use one of its implementations to use it. The java.util.concurrent package has the following implementations of the BlockingQueue interface (in Java 6): - -ArrayBlockingQueue -DelayQueue -LinkedBlockingQueue -PriorityBlockingQueue -SynchronousQueue -Click the links in the list to read more about each implementation. If a link cannot be clicked, that implementation has not yet been described. Check back again in the future, or check out the JavaDoc's for more detail. - -##Java BlockingQueue Example - -Here is a Java BlockingQueue example. The example uses the ArrayBlockingQueue implementation of the BlockingQueue interface. - -First, the BlockingQueueExample class which starts a Producer and a Consumer in separate threads. The Producer inserts strings into a shared BlockingQueue, and the Consumer takes them out. - -public class BlockingQueueExample { - - public static void main(String[] args) throws Exception { - - BlockingQueue queue = new ArrayBlockingQueue(1024); - - Producer producer = new Producer(queue); - Consumer consumer = new Consumer(queue); - - new Thread(producer).start(); - new Thread(consumer).start(); - - Thread.sleep(4000); - } -} -Here is the Producer class. Notice how it sleeps a second between each put() call. This will cause the Consumer to block, while waiting for objects in the queue. - -public class Producer implements Runnable{ - - protected BlockingQueue queue = null; - - public Producer(BlockingQueue queue) { - this.queue = queue; - } - - public void run() { - try { - queue.put("1"); - Thread.sleep(1000); - queue.put("2"); - Thread.sleep(1000); - queue.put("3"); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } -} -Here is the Consumer class. It just takes out the objects from the queue, and prints them to System.out. - -public class Consumer implements Runnable{ - - protected BlockingQueue queue = null; - - public Consumer(BlockingQueue queue) { - this.queue = queue; - } - - public void run() { - try { - System.out.println(queue.take()); - System.out.println(queue.take()); - System.out.println(queue.take()); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } -} \ No newline at end of file From 261e22a428cd65152f1e01de6a3a66a83230df4d Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 16:30:26 +0800 Subject: [PATCH 399/524] Published with https://stackedit.io/ --- ...7\357\274\210BlockingQueue\357\274\211.md" | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 "Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" new file mode 100644 index 0000000..39fa489 --- /dev/null +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -0,0 +1,113 @@ +#02.阻塞队列(BlockingQueue) + +The Java BlockingQueue interface in the java.util.concurrent class represents a queue which is thread safe to put into, and take instances from. In this text I will show you how to use this BlockingQueue. + +This text will not discuss how to implement a BlockingQueue in Java yourself. If you are interested in that, I have a text on Blocking Queues in my more theoretical Java Concurrency Tutorial. + +##BlockingQueue Usage + +A BlockingQueue is typically used to have on thread produce objects, which another thread consumes. Here is a diagram that illustrates this principle: + +A BlockingQueue with one thread putting into it, and another thread taking from it. +A BlockingQueue with one thread putting into it, and another thread taking from it. +The producing thread will keep producing new objects and insert them into the queue, until the queue reaches some upper bound on what it can contain. It's limit, in other words. If the blocking queue reaches its upper limit, the producing thread is blocked while trying to insert the new object. It remains blocked until a consuming thread takes an object out of the queue. + +The consuming thread keeps taking objects out of the blocking queue, and processes them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue. + + +##BlockingQueue Methods + +A BlockingQueue has 4 different sets of methods for inserting, removing and examining the elements in the queue. Each set of methods behaves differently in case the requested operation cannot be carried out immediately. Here is a table of the methods: + + Throws Exception Special Value Blocks Times Out +Insert add(o) offer(o) put(o) offer(o, timeout, timeunit) +Remove remove(o) poll(o) take(o) poll(timeout, timeunit) +Examine element(o) peek(o) +The 4 different sets of behaviour means this: + +Throws Exception: +If the attempted operation is not possible immediately, an exception is thrown. +Special Value: +If the attempted operation is not possible immediately, a special value is returned (often true / false). +Blocks: +If the attempted operation is not possible immedidately, the method call blocks until it is. +Times Out: +If the attempted operation is not possible immedidately, the method call blocks until it is, but waits no longer than the given timeout. Returns a special value telling whether the operation succeeded or not (typically true / false). +It is not possible to insert null into a BlockingQueue. If you try to insert null, the BlockingQueue will throw a NullPointerException. + +It is also possible to access all the elements inside a BlockingQueue, and not just the elements at the start and end. For instance, say you have queued an object for processing, but your application decides to cancel it. You can then call e.g. remove(o) to remove a specific object in the queue. However, this is not done very efficiently, so you should not use these Collection methods unless you really have to. + +##BlockingQueue Implementations + +Since BlockingQueue is an interface, you need to use one of its implementations to use it. The java.util.concurrent package has the following implementations of the BlockingQueue interface (in Java 6): + +ArrayBlockingQueue +DelayQueue +LinkedBlockingQueue +PriorityBlockingQueue +SynchronousQueue +Click the links in the list to read more about each implementation. If a link cannot be clicked, that implementation has not yet been described. Check back again in the future, or check out the JavaDoc's for more detail. + +##Java BlockingQueue Example + +Here is a Java BlockingQueue example. The example uses the ArrayBlockingQueue implementation of the BlockingQueue interface. + +First, the BlockingQueueExample class which starts a Producer and a Consumer in separate threads. The Producer inserts strings into a shared BlockingQueue, and the Consumer takes them out. + +public class BlockingQueueExample { + + public static void main(String[] args) throws Exception { + + BlockingQueue queue = new ArrayBlockingQueue(1024); + + Producer producer = new Producer(queue); + Consumer consumer = new Consumer(queue); + + new Thread(producer).start(); + new Thread(consumer).start(); + + Thread.sleep(4000); + } +} +Here is the Producer class. Notice how it sleeps a second between each put() call. This will cause the Consumer to block, while waiting for objects in the queue. + +public class Producer implements Runnable{ + + protected BlockingQueue queue = null; + + public Producer(BlockingQueue queue) { + this.queue = queue; + } + + public void run() { + try { + queue.put("1"); + Thread.sleep(1000); + queue.put("2"); + Thread.sleep(1000); + queue.put("3"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} +Here is the Consumer class. It just takes out the objects from the queue, and prints them to System.out. + +public class Consumer implements Runnable{ + + protected BlockingQueue queue = null; + + public Consumer(BlockingQueue queue) { + this.queue = queue; + } + + public void run() { + try { + System.out.println(queue.take()); + System.out.println(queue.take()); + System.out.println(queue.take()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file From b5c3ed78e956cb6f14f9ed7a6c1a70eb748caa67 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 16:31:24 +0800 Subject: [PATCH 400/524] Published with https://stackedit.io/ --- ...0\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" index 39fa489..85bfbca 100644 --- "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -8,8 +8,8 @@ This text will not discuss how to implement a BlockingQueue in Java yourself. If A BlockingQueue is typically used to have on thread produce objects, which another thread consumes. Here is a diagram that illustrates this principle: -A BlockingQueue with one thread putting into it, and another thread taking from it. -A BlockingQueue with one thread putting into it, and another thread taking from it. + + The producing thread will keep producing new objects and insert them into the queue, until the queue reaches some upper bound on what it can contain. It's limit, in other words. If the blocking queue reaches its upper limit, the producing thread is blocked while trying to insert the new object. It remains blocked until a consuming thread takes an object out of the queue. The consuming thread keeps taking objects out of the blocking queue, and processes them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue. From 346c8dbcd2363d1d191a471ba7b07c961fee76b6 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 16:44:20 +0800 Subject: [PATCH 401/524] Published with https://stackedit.io/ --- ...\210\227\357\274\210BlockingQueue\357\274\211.md" | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" index 85bfbca..5f568e3 100644 --- "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -1,10 +1,8 @@ #02.阻塞队列(BlockingQueue) -The Java BlockingQueue interface in the java.util.concurrent class represents a queue which is thread safe to put into, and take instances from. In this text I will show you how to use this BlockingQueue. +在Java `java.util.concurrent`包中的*BlockingQueue*类是一个线程安全的阻塞队列类,在这个类中,入列和出类的操作都是线程安全的。 -This text will not discuss how to implement a BlockingQueue in Java yourself. If you are interested in that, I have a text on Blocking Queues in my more theoretical Java Concurrency Tutorial. - -##BlockingQueue Usage +##BlockingQueue用法(BlockingQueue Usage) A BlockingQueue is typically used to have on thread produce objects, which another thread consumes. Here is a diagram that illustrates this principle: @@ -15,7 +13,7 @@ The producing thread will keep producing new objects and insert them into the qu The consuming thread keeps taking objects out of the blocking queue, and processes them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue. -##BlockingQueue Methods +##BlockingQueue的方法(BlockingQueue Methods) A BlockingQueue has 4 different sets of methods for inserting, removing and examining the elements in the queue. Each set of methods behaves differently in case the requested operation cannot be carried out immediately. Here is a table of the methods: @@ -37,7 +35,7 @@ It is not possible to insert null into a BlockingQueue. If you try to insert nul It is also possible to access all the elements inside a BlockingQueue, and not just the elements at the start and end. For instance, say you have queued an object for processing, but your application decides to cancel it. You can then call e.g. remove(o) to remove a specific object in the queue. However, this is not done very efficiently, so you should not use these Collection methods unless you really have to. -##BlockingQueue Implementations +##BlockingQueue的实现类(BlockingQueue Implementations) Since BlockingQueue is an interface, you need to use one of its implementations to use it. The java.util.concurrent package has the following implementations of the BlockingQueue interface (in Java 6): @@ -48,7 +46,7 @@ PriorityBlockingQueue SynchronousQueue Click the links in the list to read more about each implementation. If a link cannot be clicked, that implementation has not yet been described. Check back again in the future, or check out the JavaDoc's for more detail. -##Java BlockingQueue Example +##BlockingQueue示例(Java BlockingQueue Example) Here is a Java BlockingQueue example. The example uses the ArrayBlockingQueue implementation of the BlockingQueue interface. From 932aa7fc202adb758619479114c4525323a4f839 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 17:12:31 +0800 Subject: [PATCH 402/524] Published with https://stackedit.io/ --- ...0\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" index 5f568e3..c5abb01 100644 --- "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -4,10 +4,12 @@ ##BlockingQueue用法(BlockingQueue Usage) -A BlockingQueue is typically used to have on thread produce objects, which another thread consumes. Here is a diagram that illustrates this principle: +阻塞队列(BlockingQueue)通常被用于**生产消费者模式**。看下面这张图:  + + The producing thread will keep producing new objects and insert them into the queue, until the queue reaches some upper bound on what it can contain. It's limit, in other words. If the blocking queue reaches its upper limit, the producing thread is blocked while trying to insert the new object. It remains blocked until a consuming thread takes an object out of the queue. The consuming thread keeps taking objects out of the blocking queue, and processes them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue. From dad7ba1c8057837f834c41a51748c5734af7159f Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 17:50:32 +0800 Subject: [PATCH 403/524] Published with https://stackedit.io/ --- ...7\357\274\210BlockingQueue\357\274\211.md" | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" index c5abb01..997dc0c 100644 --- "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -1,6 +1,6 @@ #02.阻塞队列(BlockingQueue) -在Java `java.util.concurrent`包中的*BlockingQueue*类是一个线程安全的阻塞队列类,在这个类中,入列和出类的操作都是线程安全的。 +在Java `java.util.concurrent`包中的*BlockingQueue*是一个线程安全的阻塞队列接口,在这个接口中,入列和出类的操作都是线程安全的。 ##BlockingQueue用法(BlockingQueue Usage) @@ -8,21 +8,25 @@  +**生产者线程**生产新的对象,并把对象插入到队列中,直到队列中元素达到上限。如果阻塞队列达到了上限,则尝试插入对象的生产者线程会进入阻塞状态,它们会一直阻塞直到有**消费者线程**从队列中取出对象。 +**消费者线程**会持续从阻塞队列中取出对象并进行相应处理。如果消费者线程试图从空的阻塞队列中取出对象,则会进入阻塞状态,直到有生产者线程向队列中插入对象。 -The producing thread will keep producing new objects and insert them into the queue, until the queue reaches some upper bound on what it can contain. It's limit, in other words. If the blocking queue reaches its upper limit, the producing thread is blocked while trying to insert the new object. It remains blocked until a consuming thread takes an object out of the queue. - -The consuming thread keeps taking objects out of the blocking queue, and processes them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue. +##BlockingQueue的方法(BlockingQueue Methods) +*BlockingQueue*分别有四种用于**入列**和**出列**的方法。每种方法都有不同的处理行为用以处理不同的应用场景: -##BlockingQueue的方法(BlockingQueue Methods) +每一套方法表现不同的情况下所请求的操作不能被立即进行。下面是该方法的一个表: A BlockingQueue has 4 different sets of methods for inserting, removing and examining the elements in the queue. Each set of methods behaves differently in case the requested operation cannot be carried out immediately. Here is a table of the methods: - Throws Exception Special Value Blocks Times Out -Insert add(o) offer(o) put(o) offer(o, timeout, timeunit) -Remove remove(o) poll(o) take(o) poll(timeout, timeunit) -Examine element(o) peek(o) +|Throws Exception| Special Value| Blocks| Times Out + ------|--------------|------------|--------------|---------------- +Insert | add(o) | offer(o) | put(o) |offer(o, timeout, timeunit) +Remove | remove(o) | poll(o)| take(o) |poll(timeout, timeunit) +Examine | element(o) | peek(o) | | + + The 4 different sets of behaviour means this: Throws Exception: From 456c3f5334a14c60a22d4a0f7d695df7fe16def3 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 17:51:47 +0800 Subject: [PATCH 404/524] Published with https://stackedit.io/ --- ...230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" index 997dc0c..e8aad5c 100644 --- "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -20,7 +20,7 @@ A BlockingQueue has 4 different sets of methods for inserting, removing and examining the elements in the queue. Each set of methods behaves differently in case the requested operation cannot be carried out immediately. Here is a table of the methods: -|Throws Exception| Special Value| Blocks| Times Out +||Throws Exception| Special Value| Blocks| Times Out ------|--------------|------------|--------------|---------------- Insert | add(o) | offer(o) | put(o) |offer(o, timeout, timeunit) Remove | remove(o) | poll(o)| take(o) |poll(timeout, timeunit) From 7f351d8ab93b46e7c3d6a5d560dad9e869e20963 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 17:54:08 +0800 Subject: [PATCH 405/524] Published with https://stackedit.io/ --- ...\227\357\274\210BlockingQueue\357\274\211.md" | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" index e8aad5c..a9aeb95 100644 --- "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -16,10 +16,6 @@ *BlockingQueue*分别有四种用于**入列**和**出列**的方法。每种方法都有不同的处理行为用以处理不同的应用场景: -每一套方法表现不同的情况下所请求的操作不能被立即进行。下面是该方法的一个表: - -A BlockingQueue has 4 different sets of methods for inserting, removing and examining the elements in the queue. Each set of methods behaves differently in case the requested operation cannot be carried out immediately. Here is a table of the methods: - ||Throws Exception| Special Value| Blocks| Times Out ------|--------------|------------|--------------|---------------- Insert | add(o) | offer(o) | put(o) |offer(o, timeout, timeunit) @@ -27,16 +23,18 @@ Remove | remove(o) | poll(o)| take(o) |poll(timeout, timeunit) Examine | element(o) | peek(o) | | -The 4 different sets of behaviour means this: +四种不同的行为含义: -Throws Exception: +* 抛出异常(Throws Exception): If the attempted operation is not possible immediately, an exception is thrown. -Special Value: +* 特殊值(Special Value): If the attempted operation is not possible immediately, a special value is returned (often true / false). -Blocks: +* 阻塞(Blocks): If the attempted operation is not possible immedidately, the method call blocks until it is. -Times Out: +* 超时(Times Out): If the attempted operation is not possible immedidately, the method call blocks until it is, but waits no longer than the given timeout. Returns a special value telling whether the operation succeeded or not (typically true / false). + + It is not possible to insert null into a BlockingQueue. If you try to insert null, the BlockingQueue will throw a NullPointerException. It is also possible to access all the elements inside a BlockingQueue, and not just the elements at the start and end. For instance, say you have queued an object for processing, but your application decides to cancel it. You can then call e.g. remove(o) to remove a specific object in the queue. However, this is not done very efficiently, so you should not use these Collection methods unless you really have to. From b7be633355edff44ad47fa58702c1e2c4bcdec94 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 18:08:11 +0800 Subject: [PATCH 406/524] Published with https://stackedit.io/ --- ...\345\210\227\357\274\210BlockingQueue\357\274\211.md" | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" index a9aeb95..4566e19 100644 --- "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -26,14 +26,13 @@ Examine | element(o) | peek(o) | | 四种不同的行为含义: * 抛出异常(Throws Exception): -If the attempted operation is not possible immediately, an exception is thrown. +如果尝试的操作不能立即执行则抛出异常。 * 特殊值(Special Value): -If the attempted operation is not possible immediately, a special value is returned (often true / false). +如果尝试的操作不能立即执行,则返回特殊值(通常为true/false)。 * 阻塞(Blocks): -If the attempted operation is not possible immedidately, the method call blocks until it is. +如果尝试的操作不能立即执行,则方法进入阻塞直到能够执行。 * 超时(Times Out): -If the attempted operation is not possible immedidately, the method call blocks until it is, but waits no longer than the given timeout. Returns a special value telling whether the operation succeeded or not (typically true / false). - +如果尝试的方法不能立即执行,则方法进入阻塞直到能够执行,但如果阻塞超过设置的超时时间,则返回一个特殊值指明操作是否成功执行(通常为true/false) It is not possible to insert null into a BlockingQueue. If you try to insert null, the BlockingQueue will throw a NullPointerException. From b0d234259b8a5a9ed7dc50ad4f9a24590db44417 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 18:20:02 +0800 Subject: [PATCH 407/524] Published with https://stackedit.io/ --- ...237\345\210\227\357\274\210BlockingQueue\357\274\211.md" | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" index 4566e19..ae327bc 100644 --- "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -34,12 +34,14 @@ Examine | element(o) | peek(o) | | * 超时(Times Out): 如果尝试的方法不能立即执行,则方法进入阻塞直到能够执行,但如果阻塞超过设置的超时时间,则返回一个特殊值指明操作是否成功执行(通常为true/false) -It is not possible to insert null into a BlockingQueue. If you try to insert null, the BlockingQueue will throw a NullPointerException. +往*BlockingQueue*中插入null是不可能的,如果你往*BlockingQueue*中插入null,则会抛出*NullPointerException*异常。 -It is also possible to access all the elements inside a BlockingQueue, and not just the elements at the start and end. For instance, say you have queued an object for processing, but your application decides to cancel it. You can then call e.g. remove(o) to remove a specific object in the queue. However, this is not done very efficiently, so you should not use these Collection methods unless you really have to. +获取*BlockingQueue*中任意的元素都是可以的,不仅限于队列的头部或尾部。举个例子,如果你已经将一个任务插入队列,但你现在想取消这个任务,你可以通过类似`remove(task)`的方法来删除特定的在*BlockingQueue*中的元素。然而,这些操作都并非高性能的,除非迫不得已,不要调用这些方法。 ##BlockingQueue的实现类(BlockingQueue Implementations) + + Since BlockingQueue is an interface, you need to use one of its implementations to use it. The java.util.concurrent package has the following implementations of the BlockingQueue interface (in Java 6): ArrayBlockingQueue From c44ed4dace7b07dcc644d7d6db8ce6e6c98a56ac Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 18:26:47 +0800 Subject: [PATCH 408/524] Published with https://stackedit.io/ --- ...7\357\274\210BlockingQueue\357\274\211.md" | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" index ae327bc..26927a9 100644 --- "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -40,27 +40,24 @@ Examine | element(o) | peek(o) | | ##BlockingQueue的实现类(BlockingQueue Implementations) +由于*BlockingQueue*只是一个接口,所以我们要用时,应该选择具体的实现类。在Java 6的*java.util.concurrent*包中包含以下*BlockingQueue*的实现类: - -Since BlockingQueue is an interface, you need to use one of its implementations to use it. The java.util.concurrent package has the following implementations of the BlockingQueue interface (in Java 6): - -ArrayBlockingQueue -DelayQueue -LinkedBlockingQueue -PriorityBlockingQueue -SynchronousQueue -Click the links in the list to read more about each implementation. If a link cannot be clicked, that implementation has not yet been described. Check back again in the future, or check out the JavaDoc's for more detail. +* ArrayBlockingQueue +* DelayQueue +* LinkedBlockingQueue +* PriorityBlockingQueue +* SynchronousQueue ##BlockingQueue示例(Java BlockingQueue Example) -Here is a Java BlockingQueue example. The example uses the ArrayBlockingQueue implementation of the BlockingQueue interface. +下面是一个*BlockingQueue*的例子,这个例子中使用了实现*BlockingQueue*接口的*ArrayBlockingQueue*类。 -First, the BlockingQueueExample class which starts a Producer and a Consumer in separate threads. The Producer inserts strings into a shared BlockingQueue, and the Consumer takes them out. +首先,这个*BlockingQueueExample*类中,分别启动了一个*Producer*和一个*Consumer*线程。*Producer*线程往共享的阻塞队列中插入数据,而*Consumer*线程从阻塞队列中取出数据并进行相应处理: +```Java public class BlockingQueueExample { public static void main(String[] args) throws Exception { - BlockingQueue queue = new ArrayBlockingQueue(1024); Producer producer = new Producer(queue); @@ -72,10 +69,12 @@ public class BlockingQueueExample { Thread.sleep(4000); } } +``` + Here is the Producer class. Notice how it sleeps a second between each put() call. This will cause the Consumer to block, while waiting for objects in the queue. +```Java public class Producer implements Runnable{ - protected BlockingQueue queue = null; public Producer(BlockingQueue queue) { @@ -94,10 +93,12 @@ public class Producer implements Runnable{ } } } +``` + Here is the Consumer class. It just takes out the objects from the queue, and prints them to System.out. +```Java public class Consumer implements Runnable{ - protected BlockingQueue queue = null; public Consumer(BlockingQueue queue) { @@ -113,4 +114,5 @@ public class Consumer implements Runnable{ e.printStackTrace(); } } -} \ No newline at end of file +} +``` \ No newline at end of file From 674e5133ed1569c068c6946d542ad03f2cc6ef41 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Tue, 23 Sep 2014 18:32:03 +0800 Subject: [PATCH 409/524] Published with https://stackedit.io/ --- ...0\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" index 26927a9..0454d9d 100644 --- "a/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" +++ "b/Java-Concurrency-Util/02.\351\230\273\345\241\236\351\230\237\345\210\227\357\274\210BlockingQueue\357\274\211.md" @@ -71,7 +71,7 @@ public class BlockingQueueExample { } ``` -Here is the Producer class. Notice how it sleeps a second between each put() call. This will cause the Consumer to block, while waiting for objects in the queue. +下面是*Producer*类的实现。注意这里的每个`put()`方法间线程都休眠了1s。这会导致等待队列元素的*Consumer*线程阻塞。 ```Java public class Producer implements Runnable{ @@ -95,7 +95,7 @@ public class Producer implements Runnable{ } ``` -Here is the Consumer class. It just takes out the objects from the queue, and prints them to System.out. +下面是*Consumer*类的实现,它仅仅只是连续从队列中取出三个元素并进行打印: ```Java public class Consumer implements Runnable{ From 78f7d841a42ea7c69af813417b39f70a4a4a9e0c Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 24 Sep 2014 01:22:31 +0800 Subject: [PATCH 410/524] Published with https://stackedit.io/ --- Java-Concurrency-Util/03.ArrayBlockingQueue.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Java-Concurrency-Util/03.ArrayBlockingQueue.md diff --git a/Java-Concurrency-Util/03.ArrayBlockingQueue.md b/Java-Concurrency-Util/03.ArrayBlockingQueue.md new file mode 100644 index 0000000..4498536 --- /dev/null +++ b/Java-Concurrency-Util/03.ArrayBlockingQueue.md @@ -0,0 +1,4 @@ +#03.ArrayBlockingQueue + + +> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file From 8a2883af65091851144f74d0638f59228278f846 Mon Sep 17 00:00:00 2001 From: cokepluscarbon <93948886@qq.com> Date: Wed, 24 Sep 2014 01:23:06 +0800 Subject: [PATCH 411/524] Published with https://stackedit.io/ --- .../03.ArrayBlockingQueue.md | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Java-Concurrency-Util/03.ArrayBlockingQueue.md b/Java-Concurrency-Util/03.ArrayBlockingQueue.md index 4498536..f640869 100644 --- a/Java-Concurrency-Util/03.ArrayBlockingQueue.md +++ b/Java-Concurrency-Util/03.ArrayBlockingQueue.md @@ -1,4 +1,22 @@ #03.ArrayBlockingQueue +The ArrayBlockingQueue class implements the BlockingQueue interface. Read the BlockingQueue text for more information about the interface. -> Written with [StackEdit](https://stackedit.io/). \ No newline at end of file +ArrayBlockingQueue is a bounded, blocking queue that stores the elements internally in an array. That it is bounded means that it cannot store unlimited amounts of elements. There is an upper bound on the number of elements it can store at the same time. You set the upper bound at instantiation time, and after that it cannot be changed. + +The ArrayBlockingQueue stores the elements internally in FIFO (First In, First Out) order. The head of the queue is the element which has been in queue the longest time, and the tail of the queue is the element which has been in the queue the shortest time. + +Here is how to instantiate and use an ArrayBlockingQueue: + +BlockingQueue queue = new ArrayBlockingQueue(1024); + +queue.put("1"); + +Object object = queue.take(); +Here is a BlockingQueue example that uses Java Generics. Notice how you can put and take String's instead of : + +BlockingQueue queue = new ArrayBlockingQueue