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

chapter 10 init

上级 11287fb7
# Chapter 10 Concurrency andSynchronizati on
> 译者:[Ruffianjiang](https://github.com/Ruffianjiang)
An implicit assumption in everyth ing we’ve done so far is that a single program ismodifying our data structures. In Java, one can have the effect of multiple programsmodifying an object, due to the existence of threads
​ 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.
## 10.1 Synchronized Data Structures
Consider the `ArrayList` implementation from §4.1. In the method `ensureCapacity`, we find
```java
public void ensureCapacity(int N) {
if (N <= data.length)
return;
Object[] newData = new Object[N];
System.arraycopy (data, 0,newData, 0, count);
data = newData;
}
```
```java
public Object set(int k, Object x) {
check (k, count);
Object old = data[k];
data[k] = x;
return old;
}
```
Suppose one program executes `ensureCapacity` while another is executing set on the same `ArrayList` object. We could see the following interleaving of their actions:
```java
/* Program 1 executes: */ newData = new Object[N];
/* Program 1 executes: */ System.arraycopy (data, 0,newData, 0, count);
/* Program 2 executes: */ data[k] = x;
/* Program 1 executes: */ data = newData;
```
Thus, we lose the value that Program 2 set, because it puts this value into th e old value of `data` after `data’s` contents h ave been copied to the new, expanded array. To solve th e 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:
```java
public class SyncArrayList<T> extends ArrayList<T> {
...
public void ensureCapacity(int n) {
synchronized (this) {
super.ensureCapacity (n);
}
}
public synchronized T set(int k, T x) {
return super.set (k, x);
}
...
}
```
​ The process of providing such wrapper functions for all methods of a List is sufficiently tedious that the standard Java library class `java.util.Collections` provides the following method:
```java
/** A synchronized (thread-safe) view of the list L, in which only
* one thread at a time executes any method. To be effective,
* (a) there should be no subsequent direct use of L,
* and (b) the returned List must be synchronized upon
* during any iteration, as in
*
* List aList = Collections.synchronizedList(new ArrayList());
* ...
* synchronized(aList) {
* for (Iterator i = aList.iterator(); i.hasNext(); )
* foo(i.next());
* }
*/
public static List<T> synchronizedList (List L<T>) { ... }
```
Unfortunately, there is a time cost associated with synchronizing on every operation, which is why the Java library designers decided that `Collection` and most of its subtypes would not be synchronized. On the other hand, `StringBuffers` and `Vectors` are synchronized, and cannot be corrupted by simultaneous use.
## 10.2 Monitors and Orderly Communication
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.
​ Monitors are exemplified by one of the classic examples: the shared buffer or mailbox. A simple version of its public specification looks like this:
```java
/** A container for a single message (an arbitrary Object). At any
* time, a SmallMailbox is either empty (containing no message) or
* full (containing one message). */
public class SmallMailbox {
/** When THIS is empty, set its current message to MESSAGE, making
* it full. */
public synchronized void deposit (Object message)
throws InterruptedException { ... }
/** When THIS is full, empty it and return its current message. */
public synchronized Object receive ()
throws InterruptedException { ... }
}
```
Since the specifications suggest that either method might have to wait for a new message to be deposited or an old one to be received, we specify both as possibly throwing an `InterruptedException`, which is the standard Java way to indicate that while we were waiting, some other thread interrupted us.
The `SmallMailbox` specification illustrates the features of a typical monitor:
- None of the modifiable state variables (i.e., fields) are exposed.
- Accesses from separate th reads that make any reference to modifiable state are mutually excluded; only one thread at a time holds a lock on a `SmallMailbox` object.
- A thread may relinquish a lock temporarily and await notification of some change. But changes in the ownership of a lock occur only at well-defined points in the program.
The internal representation is simple:
```java
private Object message;
private boolean amFull;
```
The implementations make use of the primitive Java features for “waiting until notified:”
```java
public synchronized void deposit (Object message)
throws InterruptedException{
while (amFull)
wait (); // Same as this.wait ();
this.message = message;
this.amFull = true;
notifyAll (); // Same as this.notifyAll ()
}
public synchronized Object receive ()
throws InterruptedException{
while (! amFull)
wait ();
amFull = false;
notifyAll ();
return message;
}
```
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`.
​ 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:
```java
class Communicate {
static SimpleMailbox
box1 = new SimpleMailbox (),
box2 = new SimpleMailbox ();
}
// Thread #1: | // Thread #2:
m1 = Communicate.box1.receive ();| m2 = Communicate.box2.receive();
Communicate.box2.deposit (msg1); | Communicate.box1.deposit (msg2);
```
Since neither thread sends anything before trying to receive a message from its box, both threads wait for each other (the problem could be solved by having one of the two threads reverse the order in which it receives and deposits).
## 10.3 Message Passing
Monitors provide a disciplined way for multiple threads to access data without stumbling over each other. Lurking behind the concept of monitor is a simple idea:
> Thinking about multiple programs executing simultaneously is hard, so don’t do it! Instead, write a bunch of one-thread programs, and have them exchange data with each other
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.
​ In the message-passing world, threads are independent sequential programs than send each other messages. They read and write messages using methods that correspond to `read` on Java `Readers`, or `print` on Java `PrintStreams`. As a result, one th read is affected by another only when it bothers to “read its messages.”
​ We can get th e effect of message passing by writing our threads to perform all interaction with each other by means of mailboxes. That is, the threads share some set of mailboxes, but share no other modifiable objects or variables (unmodifiable objects, like Strings, are fine to share)
## Exercises
**10.1** Give a possible implementation for the `Collections.synchronizedList` static method in §10.1.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册