# Chapter 10 Concurrency andSynchronizati on

> 译者：[Ruffianjiang](https://github.com/Ruffianjiang)

An implicit assumption in everything we’ve done so far is that a single program is modifying our data structures. In Java, one can have the eﬀect of multiple programs modifying 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 ﬁve 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 “ﬁnalizing” 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 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

Consider the `ArrayList` implementation from §4.1. In the method `ensureCapacity`, we ﬁnd

```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 the old value of `data` after `data’s` contents have 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 modiﬁer 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 suﬃciently 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 exempliﬁed by one of the classic examples: the shared buﬀer or mailbox. A simple version of its public speciﬁcation 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 speciﬁcations 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` speciﬁcation illustrates the features of a typical monitor:

- None of the modiﬁable state variables (i.e., ﬁelds) are exposed.

- Accesses from separate threads that make any reference to modiﬁable 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 notiﬁcation of some change. But changes in the ownership of a lock occur only at well-deﬁned 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 notiﬁed:”

```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 the eﬀect of causing some change to the instance variables of `this`—some change, that is, that could be eﬀected 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 indeﬁnitely, as in this artiﬁcial 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 deﬁne “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 thread is aﬀected by another only when it bothers to “read its messages.”

​	We can get the eﬀect 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 modiﬁable objects or variables (unmodiﬁable objects, like Strings, are ﬁne to share)

## Exercises

**10.1** Give a possible implementation for the `Collections.synchronizedList` static method in §10.1.
