Section 30.2 Chapter 30 · Actors and Concurrency 608
ifying or accessing that might be modified or accessed by other threads, and
what locks are being held. At each method call, you must reason about what
locks it will try to hold, and convince yourself that it will not deadlock while
trying to obtain them. Compounding the problem, the locks you reason about
are not fixed at compile time, because the program is free to create new locks
at run time as it progresses.
Making things worse, testing is not reliable with multi-threaded code.
Since threads are non-deterministic, you might successfully test a program
one thousand times, yet still the program could go wrong the first time it
runs on a customer’s machine. With shared data and locks, you must get the
program correct through reason alone.
Moreover, you can’t solve the problem by over-synchronizing either. It
can be just as problematic to synchronize everything as it is to synchronize
nothing. The problem is that new lock operations remove possibilities for
race conditions, but simultaneously add possibilities for deadlocks. A correct
lock-using program must have neither race conditions nor deadlocks, so you
cannot play it safe by overdoing it in either direction.
Java 5 introduced java.util.concurrent, a library of concurrency
utilities that provides higher level abstractions for concurrent programming.
Using the concurrency utilities makes multi-threaded programming far less
error prone than rolling your own abstractions with Java’s low-level synchro-
nization primitives. Nevertheless, the concurrent utilities are also based on
the shared data and locks model, and as a result do not solve the fundamental
difficulties of using that model.
Scala’s actors library does address the fundamental problem by providing
an alternative, share-nothing, message-passing model that programmers tend
to find much easier to reason about. Actors are a good first tool of choice
when designing concurrent software, because they can help you avoid the
deadlocks and race conditions that are easy to fall into when using the shared
data and locks model.
30.2 Actors and message passing
An actor is a thread-like entity that has a mailbox for receiving messages.
To implement an actor, you subclass scala.actors.Actor and implement
the act method. An example is shown in Listing 30.1. This actor doesn’t do
anything with its mailbox. It just prints a message five times and quits.
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index