提交 fbb365a8 编写于 作者: sinat_29705095's avatar sinat_29705095

翻译结束

上级 21fb8982
......@@ -6,7 +6,7 @@ An implicit assumption in everything we’ve done so far is that a single progra
​ Although the language used to describe threads suggests that their purpose is to allow several things to happen simultaneously, this is a somewhat misleading impression. Even the smallest Java application running on Sun ’s JDK platform, for example, has five threads, and that’s only if the application has not created any itself, and even if the machine on which the program runs consists of a single processor (which can only execute one instruction at a time). The four additional “system threads” perform a number of tasks (such as “finalizing” objects that are no longer reachable by the program) that are logically independent of the rest of the program.Their actions could usefully occur at any time relative to the rest of the program.Sun’s Java run time system, in other words, is using threads as a organizational tool for its system.
​ Threads abound in Java programs that use graphical user interfaces(GUIs). One thread draws or redraws the screen. Another responds to e vents such as the clicking of a mouse button at some point on the screen. These are related,but largely independent activities: objects must be redrawn, for example, whenever a window becomes invisible and uncovers them, which happens independently of any calculations the program is doing.Threads violate our implicit assumption that a single program operates on our data, so that even an otherwise perfectly implemented data structure, with all of its instance variables private, can become corrupted in rather bizarre ways. The existence of multiple threads operating on the same data objects also raises the general problem of how these threads are to communicate with each other in an orderly fashion.
​ Threads abound in Java programs that use graphical user interfaces(GUIs). One thread draws or redraws the screen. Another responds to events such as the clicking of a mouse button at some point on the screen. These are related,but largely independent activities: objects must be redrawn, for example, whenever a window becomes invisible and uncovers them, which happens independently of any calculations the program is doing.Threads violate our implicit assumption that a single program operates on our data, so that even an otherwise perfectly implemented data structure, with all of its instance variables private, can become corrupted in rather bizarre ways. The existence of multiple threads operating on the same data objects also raises the general problem of how these threads are to communicate with each other in an orderly fashion.
## 10.1 Synchronized Data Structures
......@@ -139,7 +139,7 @@ public synchronized Object receive ()
}
```
The methods of `SmallMailbox` allow other threads in only at carefully controlled points: the calls to wait. For example, the loop in `deposit` means “If there is still old unreceived mail, wait until some other thread to receives it and wakes me up again (with `notifyAll`) and I have managed to lock this mailbox again.” From the point of view of a thread that is executing `deposit` or `receive`, each call to `wait` has th e effect of causing some change to the in stance variables of `this`—some change, that is, that could be effected by other calls `deposit` or `receive`.
The methods of `SmallMailbox` allow other threads in only at carefully controlled points: the calls to wait. For example, the loop in `deposit` means “If there is still old unreceived mail, wait until some other thread to receives it and wakes me up again (with `notifyAll`) and I have managed to lock this mailbox again.” From the point of view of a thread that is executing `deposit` or `receive`, each call to `wait` has the effect of causing some change to the instance variables of `this`—some change, that is, that could be effected by other calls `deposit` or `receive`.
​ As long as the threads of a program are careful to protect all their data in monitors in this fashion, they will avoid the sorts of bizarre interaction described at the beginning of §10.1. Of course, there is no such thing as a free lunch; the use of locking can lead to the situation known as deadlock in which two or more threads wait for each other indefinitely, as in this artificial example:
......
......@@ -2,15 +2,11 @@
> 译者:[Ruffianjiang](https://github.com/Ruffianjiang)
到目前为止,我们所做的每件事都隐含着一个假设,即一个程序正在修改我们的数据结构。在Java中,由于线程的存在,可能会产生多个程序使对象的效果
到目前为止,我们所做的每件事都隐含着一个假设,即一个程序正在修改我们的数据结构。在Java中,由于线程的存在,可能会产生多个程序使对象的效果
Although the language used to describe threads suggests that their purpose is to allow several things to happen simultaneously, this is a somewhat misleading impression. Even the smallest Java application running on Sun ’s JDK platform, for example, has five threads, and that’s only if the application has not created any itself, and even if the machine on which the program runs consists of a single processor (which can only execute one instruction at a time). The four additional “system threads” perform a number of tasks (such as “finalizing” objects that are no longer reachable by the program) that are logically independent of the rest of the program.Their actions could usefully occur at any time relative to the rest of the program.Sun’s Java run time system, in other words, is using threads as a organizational tool for its system.
尽管用于描述线程的语言表明,线程的目的是允许同时发生几件事情,但这在一定程度上是一种误导。即使是最小的Java应用程序运行在 Sun 的 JDK 的平台上,例如,有五个线程,这是只有在应用程序没有创建任何本身,即使程序运行的机器由一个单处理器(一次只能执行一个指令)。这四个额外的“系统线程”执行许多任务(例如“finalizing”对象是程序不再可访问),这些任务在逻辑上独立于程序的其余部分。相对于程序的其余部分,它们的操作可以在任何时候有效地发生。换句话说,Sun的Java运行时系统使用线程作为其系统的组织工具。
尽管用于描述线程的语言表明,线程的目的是允许同时发生几件事情,但这在一定程度上是一种误导。即使是最小的Java应用程序运行在太阳的JDK的平台,例如,有五个线程,这是只有在应用程序没有创建任何本身,即使程序运行的机器由一个单处理器(一次只能执行一个指令)。这四个额外的“系统线程”执行许多任务(例如“终结”程序不再可访问的对象),这些任务在逻辑上独立于程序的其余部分。相对于程序的其余部分,它们的操作可以在任何时候有效地发生。换句话说,Sun的Java运行时系统使用线程作为其系统的组织工具。
​ Threads abound in Java programs that use graphical user interfaces(GUIs). One thread draws or redraws the screen. Another responds to e vents such as the clicking of a mouse button at some point on the screen. These are related,but largely independent activities: objects must be redrawn, for example, whenever a window becomes invisible and uncovers them, which happens independently of any calculations the program is doing.Threads violate our implicit assumption that a single program operates on our data, so that even an otherwise perfectly implemented data structure, with all of its instance variables private, can become corrupted in rather bizarre ways. The existence of multiple threads operating on the same data objects also raises the general problem of how these threads are to communicate with each other in an orderly fashion.
使用图形用户界面(gui)的Java程序中有大量线程。一个线程绘制或重绘屏幕。另一个响应e通风口,如点击鼠标按钮在屏幕上的某个点。这些都是相关的,但在很大程度上是独立的活动:例如,当一个窗口变得不可见并显示它们时,必须重新绘制对象,这与程序正在执行的任何计算无关。线程违反了我们的隐含假设,即一个程序对我们的数据进行操作,因此,即使是一个完全实现的数据结构,其所有实例变量都是私有的,也可能以相当奇怪的方式受到破坏。在相同数据对象上运行的多个线程的存在也提出了一个普遍的问题,即这些线程如何以有序的方式彼此通信。
​ 使用图形用户界面(GUIs)的Java程序中有大量线程。一个线程绘制或重绘屏幕。另一个响应事件,如点击鼠标按钮在屏幕上的某个点。这些都是相关的,但在很大程度上是独立的活动:例如,当一个窗口变得不可见并显示它们时,必须重新绘制对象,这与程序正在执行的任何计算无关。线程违反了我们的隐含假设,即一个程序对我们的数据进行操作,因此,即使是一个完全实现的数据结构,其所有实例变量都是私有的,也可能以相当奇怪的方式受到破坏。在相同数据对象上运行的多个线程的存在也提出了一个普遍的问题,即这些线程如何以有序的方式彼此通信。
## 10.1 同步的数据结构
......@@ -36,7 +32,7 @@ public Object set(int k, Object x) {
}
```
假设一个程序执行 `ensureCapacity` ,而另一个程序正在相同的 `ArrayList` 对象上执行改动。我们可以看到他们的动作交叉在了一起,如下所示:
假设一个程序执行 `ensureCapacity` ,而另一个程序正在相同的 `ArrayList` 对象上执行改动。我们可以看到他们的动作交叉在了一起,如下所示:
```java
/* Program 1 executes: */ newData = new Object[N];
/* Program 1 executes: */ System.arraycopy (data, 0,newData, 0, count);
......@@ -44,9 +40,7 @@ public Object set(int k, Object x) {
/* Program 1 executes: */ data = newData;
```
Thus, we lose the value that Program 2 set, because it puts this value into the old value of `data` after `data’s` contents have been copied to the new expanded array. To solve the simple problem presented by `ArrayList`, threads can arrange to access any particular `ArrayList` in mutual exclusion—that is, in such a way that only one thread at a time operates on the object. Java’s `synchronized` statement provide mutual exclusion, allowing us to produce `synchronized` (or thread-safe) data structures. Here is part of an example, showing both the use of the `synchronized` method modifier and equivalent use of the synchronized statement:
因此,我们丢失了程序2设置的值,因为它在 `data` 的内容复制到新的扩展数组之后,将这个值放入 `data` 的旧值中。为了解决 `ArrayList` 呈现出的简单问题,线程可以以互斥的方式安排访问任何特定的 `ArrayList` —— 也就是说,每次只有一个线程操作对象。Java的“synchronized”语句提供互斥,允许我们生成“synchronized”(或线程安全)数据结构。下面是一个例子的一部分,展示了同步方法修饰符的使用和同步语句的等效使用:
​ 因此,我们丢失了 `Program 2` 设置的值,因为它在 `data` 的内容复制到新的扩展数组之后,将这个值放入 `data` 的旧值中。为了解决 `ArrayList` 呈现出的简单问题,线程可以以互斥的方式安排访问任何特定的 `ArrayList` —— 也就是说,每次只有一个线程操作对象。Java的 `synchronized` 语句提供互斥,允许我们生成 `synchronized` (或线程安全)数据结构。下面是一个例子的一部分,展示了`synchronized`方法修饰符的使用和同步语句的等效使用:
```java
public class SyncArrayList<T> extends ArrayList<T> {
...
......@@ -62,7 +56,7 @@ public class SyncArrayList<T> extends ArrayList<T> {
}
```
为所有方法提供这样的包装函数清单的过程非常繁琐,以至于标准Java库类的 `java.util.Collections` 提供了以下方法:
​ 为所有方法提供这样的包装函数清单的过程非常繁琐,以至于标准Java库类的 `java.util.Collections` 提供了以下方法:
```java
/** A synchronized (thread-safe) view of the list L, in which only
* one thread at a time executes any method. To be effective,
......@@ -80,17 +74,13 @@ public class SyncArrayList<T> extends ArrayList<T> {
public static List<T> synchronizedList (List L<T>) { ... }
```
不幸的是,每个操作的同步都有时间开销,这就是为什么Java库设计人员决定不同步 `Collection` 及其大多数子类型。另一方面,`StringBuffers``Vectors` 是同步的,不能被同时使用而损坏。
不幸的是,每个操作的同步都有时间开销,这就是为什么Java库设计人员决定不同步 `Collection` 及其大多数子类型。另一方面,`StringBuffers``Vectors` 是同步的,不能被同时使用而损坏。
## 10.2 监控与有序通信
The objects returned by the `synchronizedList` method are examples of the simplest kind of monitor. This term refers to an object (or type of object) that controls (“monitors”) concurrent access to some data structure so as to make it work correctly. One function of a monitor is to provide mutually exclusive access to the operations of the data structure, where needed. Another is to arrange for synchronization between threads—so that one thread can wait until an object is “ready” to provide it with some service.
“synchronizedList”方法返回的对象是最简单的监视器的例子。这个术语指的是控制(“监视器”)对某些数据结构的并发访问以使其正确工作的对象(或对象类型)。监视器的一个功能是在需要时提供对数据结构操作的互斥访问。另一种方法是安排线程之间的同步——这样一个线程就可以等待对象“准备好”为它提供一些服务。
​ Monitors are exemplified by one of the classic examples: the shared buffer or mailbox. A simple version of its public specification looks like this:
`synchronizedList` 方法返回的对象是最简单的监视器的例子。这个术语指的是控制(“监视器”)对某些数据结构的并发访问以使其正确工作的对象(或对象类型)。监视器的一个功能是在需要时提供对数据结构操作的互斥访问。另一种方法是安排线程之间的同步——这样一个线程就可以等待对象“准备好”为它提供一些服务。
监视器可以用一个典型的例子来说明:共享缓冲区或邮箱。其公共规范的一个简单版本如下:
​ 监视器可以用一个典型的例子来说明:共享缓冲区或邮箱。其公共规范的一个简单版本如下:
```java
/** A container for a single message (an arbitrary Object). At any
......@@ -107,21 +97,21 @@ public class SmallMailbox {
}
```
自规范表明这两种方法都可能需要等待新的消息沉积或接收旧,我们尽可能地将两者都指定为抛出 `InterruptedException` ,这是标准Java方式表明,我们在等待时,其他线程打断我们。
​ 自规范表明这两种方法都可能需要等待新的消息沉积或接收旧,我们尽可能地将两者都指定为抛出 `InterruptedException` ,这是标准Java方式表明,我们在等待时,其他线程打断我们。
“SmallMailbox”规范说明了典型监视器的特性:
- 没有任何可修改的状态变量(即,字段)是公开的。
​ “SmallMailbox” 规范说明了典型监视器的特性:
- 没有任何可修改的状态变量(即,字段)是公开的。
- 从单独的线程访问,使任何对可修改状态的引用相互排除;每次只有一个线程持有 `SmallMailbox` 对象上的锁。
- 线程可以暂时放弃锁,等待某些更改的通知。但是锁的所有权的变化只发生在程序中定义良好的点上。
内部表示很简单:
内部表示很简单:
```java
private Object message;
private boolean amFull;
```
这些实现使用了基本的Java特性来“等待直到被通知”:
​ 这些实现使用了基本的Java特性来“等待直到被通知”:
```java
public synchronized void deposit (Object message)
......@@ -142,14 +132,9 @@ public synchronized Object receive ()
}
```
The methods of `SmallMailbox` allow other threads in only at carefully controlled points: the calls to wait. For example, the loop in `deposit` means “If there is still old unreceived mail, wait until some other thread to receives it and wakes me up again (with `notifyAll`) and I have managed to lock this mailbox again.” From the point of view of a thread that is executing `deposit` or `receive`, each call to `wait` has th e effect of causing some change to the in stance variables of `this`—some change, that is, that could be effected by other calls `deposit` or `receive`.
`SmallMailbox` 的方法只允许其他线程进入精心控制的点:等待的调用。例如,`deposit` 中的循环表示“如果仍然有旧的未接收邮件,请等到其他线程接收到它并再次唤醒我(使用 `notifyAll` ),然后我再次锁定了这个邮箱”。从执行 `deposit``receive` 的线程的角度来看,每次调用 `wait` 都会对 `this` 的实例变量造成一些变化——可能会受到其他调用 `deposit``receive` 的影响。
“SmallMailbox”的方法只允许其他线程进入精心控制的点:等待的调用。例如,“deposit”中的循环表示“如果仍然有旧的未接收邮件,请等到其他线程接收到它并再次唤醒我(使用‘notifyAll’),然后我再次锁定了这个邮箱”。“从执行‘deposit’或‘receive’的线程的角度来看,每次调用‘wait’都会对‘this’的in stance变量造成一些变化——一些变化可能会受到其他调用‘deposit’或‘receive’的影响。
​ As long as the threads of a program are careful to protect all their data in monitors in this fashion, they will avoid the sorts of bizarre interaction described at the beginning of §10.1. Of course, there is no such thing as a free lunch; the use of locking can lead to the situation known as deadlock in which two or more threads wait for each other indefinitely, as in this artificial example:
只要程序的线程小心翼翼地以这种方式保护它们在监视器中的所有数据,它们就会避免§10.1开头描述的那种奇怪的交互。当然,天下没有免费的午餐;使用锁会导致死锁的情况,即两个或多个线程无限期地等待对方,如下面的人为例子所示:
​ 只要程序的线程小心翼翼地以这种方式保护它们在监视器中的所有数据,它们就会避免 10.1节开头描述的那种奇怪的交互。当然,天下没有免费的午餐;使用锁会导致死锁的情况,即两个或多个线程无限期地等待对方,如下面的人为例子所示:
```java
......@@ -163,22 +148,20 @@ m1 = Communicate.box1.receive ();| m2 = Communicate.box2.receive();
Communicate.box2.deposit (msg1); | Communicate.box1.deposit (msg2);
```
由于两个线程在试图从其消息框中接收消息之前都不发送任何消息,所以两个线程都彼此等待(可以通过让其中一个线程反转接收和存储消息的顺序来解决这个问题)
​ 由于两个线程在试图从其消息框中接收消息之前都不发送任何消息,所以两个线程都彼此等待(可以通过让其中一个线程反转接收和存储消息的顺序来解决这个问题)
## 10.3 消息传递
监视器(Monitors)为多个线程提供了一种有序的方法来访问数据,而不会互相阻碍。隐藏在监视器概念背后的是一个简单的想法:
​ 监视器(Monitors)为多个线程提供了一种有序的方法来访问数据,而不会互相阻碍。隐藏在监视器概念背后的是一个简单的想法:
> 考虑到同时执行多个程序是很困难的,所以不要这样做!相反,编写一组单线程程序,让它们彼此交换数据
In the case of general monitors, “exchanging data” means setting variables that each can see. If we take the idea further, we can in stead define “exchanging data” as “reading input and writing output.” We get a concurrent programming discipline called message passing.
对于一般监视器,“交换数据”意味着设置每个监视器都可以看到的变量。如果我们更进一步,我们可以将“交换数据”定义为“读取输入和写入输出”。“我们有一个并发的编程规则,叫做消息传递。
​ 对于一般监视器,“交换数据”意味着设置每个监视器都可以看到的变量。如果我们更进一步,我们可以将“交换数据”定义为“读取输入和写入输出”。“我们有一个并发的编程规则,叫做消息传递。
​在消息传递的世界中,线程是独立的顺序程序,而不是互相发送消息。他们读写消息使用是在 Java 的 `reader` 上读或在 Java 的 `PrintStreams` 上打印一致的方法。因此,只有当一个线程费力的“读取其消息”时,才会受到另一个线程的影响。
在消息传递的世界中,线程是独立的顺序程序,而不是互相发送消息。他们读写消息使用是在 Java 的 `reader` 上读或在 Java 的 `PrintStreams` 上打印一致的方法。因此,只有当一个线程费力的“读取其消息”时,才会受到另一个线程的影响。
我们可以通过编写线程来实现消息传递的效果,通过邮箱来实现所有的交互。也就是说,线程共享一组邮箱,但是不共享其他可修改的对象或变量(不可修改的对象,比如`Strings`,可以共享)
我们可以通过编写线程来实现消息传递的效果,通过邮箱来实现所有的交互。也就是说,线程共享一组邮箱,但是不共享其他可修改的对象或变量(不可修改的对象,比如`Strings`,可以共享)
## 练习
**10.1** 给10.1节的 `Collections.synchronizedList` 提供一个可能的静态方法的实现。
**10.1** 给10.1节的 `Collections.synchronizedList` 提供一个可能的静态方法的实现。
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册