img
. . . . .
Statics in Java are just global variables that are associated with a specific class. It was somewhat
convenient to use these in the single-threaded programs of yore, but in MT programs they are
disasters waiting to strike. You should reconsider your use of statics very carefully. If you do use
'em, lock 'em first!
Synchronization Variables
To provide synchronization, a system includes special data structures, and a set of functions
manipulate them. POSIX defines three synchronization variables and the function
pthread_join() to provide this functionality. (UNIX98 makes it four.) Win32 provides
synchronization variables of a slightly different nature. Java provides the same functionality by
encapsulating synchronization variables within every object. These synchronization variables are
manipulated by means of a keyword (synchronized), thread.join(), and several methods
on Object. In all the libraries, these provide the only reliable means of coordinating the
interactions of your threads. There are other tricky things you can do to coordinate your threads,
but they won't work reliably because the hardware is designed assuming that you will be using
synchronization variables (see Bus Architectures).
There are two basic things you want to do. The first is that you want to protect shared data. This is
what locks do. The second is that you want to prevent threads from running when there's nothing
for them to do. You don't want them spinning, wasting time. This is what semaphores, condition
variables, wait sets, join(), barriers, etc., are for. Once again, we will describe how the simpler
primitives in POSIX work, then show how Java maps onto them.
Mutexes
The mutual exclusion lock is the simplest and most primitive synchronization variable. It provides
a single, absolute owner for the section of code (thus a critical section) that it brackets between the
calls to pthread_mutex_lock() and pthread_mutex_unlock() (Code Example 6-3). The
first thread that locks the mutex gets ownership, and any subsequent attempts to lock it will fail,
causing the calling thread to go to sleep. When the owner unlocks it, one of the sleepers will be
awakened, made runnable, and given the chance to obtain ownership. It is possible that some
other thread will call pthread_mutex_lock() and get ownership before the newly awakened
thread does. This is perfectly correct behavior and must not affect the correctness of your
program.[2] It's unusual to write code that would be affected by this behavior (see FIFO Mutexes).
[2]
In the absurd case of two threads trying to increment a counter, it is possible that only one of
them will ever run, even though the program was written "correctly." The probability of T1 failing to
get the mutex 1000 times in a row is normally tiny and is only of interest to the rarest of non-
realtime programs.
Example 6-3 Using Mutexes in the Various Libraries
POSIX
Win32
Java
pthread_mutex_lock(m)
WaitForSingleObject(m)
synchronized(o) {
...
...
...
pthread_mutex_unlock(m)
ReleaseMutex(m)
}
In Figure 6-1, three threads all need a mutex. They have different priorities ("P:"), which
determine the order in which they go onto the sleep queue. The threads have requested the lock in
the order T1, T2, T3. As the first to try, T1 owns the lock, and T3 will be awakened as soon as T1
releases it, even though T2 requested the lock before T3.
Search WWH :
Custom Search
Previous Page
Multithreaded Programming with JAVA - Topic Index
Next Page
Multithreaded Programming with JAVA - Bookmarks
Home