Section 30.5 Chapter 30 · Actors and Concurrency 621
The best way to ensure that message objects are thread-safe is to only
use immutable objects for messages. Instances of any class that has only val
fields, which themselves refer only to immutable objects, are immutable. An
easy way to define such message classes, of course, is as case classes. So
long as you don’t explicitly add var fields to a case class and ensure the
val fields are all immutable types, your case class will by definition be im-
mutable. It will also be convenient for pattern matching in the partial func-
tions passed to react or receive. You can also use as messages instances
of regular (non-case) immutable classes that you define. Or you can use in-
stances of the many immutable classes provided in the Scala API, such as
tuples, strings, lists, immutable sets and maps, and so on.
Now, if an actor sends a mutable, unsynchronized object as a message,
and never reads or writes that object thereafter, it would work, but it’s just
asking for trouble. A future maintainer may not realize the object is shared
and write to it, thereby creating a hard to find concurrency bug.
In general, it is best to arrange your data such that every unsynchronized,
mutable object is “owned,” and therefore accessed by, only one actor. You
can arrange for objects to be transferred from one actor to another if you like,
but you need to make sure that at any given time, it is clear which actor owns
the object and is allowed to access it. In other words, when you design an
actors-based system, you need to decide which parts of mutable memory are
assigned to which actor. All other actors that access a mutable data structure
must send messages to the data structure’s owner and wait for a message to
come back with a reply.
If you do find you have a mutable object you want to continue using as
well as send in a message to another actor, you should make and send an
copy of it instead. While you’re at it, you may want to make it immutable.
For example, because arrays are mutable and unsynchronized, any array you
use should be accessed by one actor at a time. If you want to continue using
an array as well as send it to another actor, you should send a copy. For
example, if the array itself holds only immutable objects, you can make a
copy with arr.clone. But you should also consider using arr.toList, and
send the resulting immutable list instead.
Immutable objects are convenient in many cases, but they really shine
for parallel systems, because they are the easiest, lowest risk way to design
thread-safe objects. When you design a program that might involve paral-
lelism in the future, whether using actors or not, you should try especially
hard to make data structures immutable.
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index